home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / screen3 / part08 < prev    next >
Encoding:
Text File  |  1991-12-19  |  81.7 KB  |  3,769 lines

  1. Newsgroups: comp.sources.unix
  2. From: jnweiger@immd4.informatik.uni-erlangen.de (Juergen Weigert)
  3. Subject: v25i048: Screen3 - multiple windows on an ASCII terminal, Part08/08
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: jnweiger@immd4.informatik.uni-erlangen.de (Juergen Weigert)
  8. Posting-Number: Volume 25, Issue 48
  9. Archive-Name: screen3/part08
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 8 (of 8)."
  18. # Contents:  screen.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Thu Dec 19 17:36:06 1991
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'screen.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'screen.c'\"
  23. else
  24. echo shar: Extracting \"'screen.c'\" \(78493 characters\)
  25. sed "s/^X//" >'screen.c' <<'END_OF_FILE'
  26. X/* Copyright (c) 1991
  27. X *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  28. X *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  29. X * Copyright (c) 1987 Oliver Laumann
  30. X *
  31. X * This program is free software; you can redistribute it and/or modify
  32. X * it under the terms of the GNU General Public License as published by
  33. X * the Free Software Foundation; either version 1, or (at your option)
  34. X * any later version.
  35. X *
  36. X * This program is distributed in the hope that it will be useful,
  37. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  38. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  39. X * GNU General Public License for more details.
  40. X *
  41. X * You should have received a copy of the GNU General Public License
  42. X * along with this program (see the file COPYING); if not, write to the
  43. X * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  44. X *
  45. X * Noteworthy contributors to screen's design and implementation:
  46. X *    Wayne Davison (davison@borland.com)
  47. X *    Patrick Wolfe (pat@kai.com, kailand!pat)
  48. X *    Bart Schaefer (schaefer@cse.ogi.edu)
  49. X *    Nathan Glasser (nathan@brokaw.lcs.mit.edu)
  50. X *    Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
  51. X *    Howard Chu (hyc@hanauma.jpl.nasa.gov)
  52. X *    Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
  53. X *    Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
  54. X *    Marc Boucher (marc@CAM.ORG)
  55. X *
  56. X ****************************************************************
  57. X */
  58. X
  59. X#ifndef lint
  60. X  static char rcs_id[] = "$Id: screen.c,v 1.106 91/10/11 11:24:50 jnweiger Exp $ FAU";
  61. X#endif
  62. X
  63. X
  64. X#if defined(BSD) || defined(sequent) || defined(pyr)
  65. X# include <strings.h>
  66. X#else
  67. X# include <string.h>
  68. X#endif
  69. X#include <sys/param.h>
  70. X#include <signal.h>
  71. X#include <ctype.h>
  72. X#include <pwd.h>
  73. X#include <fcntl.h>
  74. X#if defined(SGI)
  75. X#include <sys/sysmacros.h>
  76. X/* #include <sys/utsname.h> we define SYSV anyway, right? */
  77. X#endif
  78. X#if !defined(sun) && !defined(B43)
  79. X# include <time.h>
  80. X#endif
  81. X#if defined(sun) || defined(_IBMR2) || defined(sysV68) || defined(MIPS) || defined(GOULD_NP1) || defined(B43)
  82. X# include <sys/time.h>
  83. X#endif
  84. X#ifdef M_XENIX
  85. X#include <sys/select.h> /* for timeval */
  86. X#endif
  87. X#include <sys/types.h>
  88. X#if !defined(sysV68) && !defined(M_XENIX)
  89. X# include <sys/wait.h>
  90. X#endif
  91. X#include <sys/stat.h>
  92. X#include <sys/file.h>
  93. X#ifndef sun
  94. X# include <sys/ioctl.h>
  95. X#endif /* sun */
  96. X
  97. X#include "config.h"
  98. X
  99. X#ifdef SVR4
  100. X#include <sys/stropts.h>
  101. X#endif
  102. X#ifdef SYSV
  103. X#include <sys/utsname.h>
  104. X#endif
  105. X
  106. X#if defined(_SEQUENT_) || defined(M_XENIX)
  107. X/* for the FD.. stuff */
  108. X# include <sys/select.h>
  109. X#endif 
  110. X#ifdef sequent
  111. X# include <sys/resource.h>
  112. X#endif /* sequent */
  113. X
  114. X#include "screen.h"
  115. X#include "patchlevel.h"
  116. X
  117. X#if defined(xelos) || defined(sysV68) || defined(M_XENIX)
  118. X struct passwd *getpwuid __P((uid_t));
  119. X struct passwd *getpwnam __P((char *));
  120. X#endif
  121. X
  122. X#ifdef USEVARARGS
  123. X# if defined(__STDC__)
  124. X#  include <stdarg.h>
  125. X# else
  126. X#  include <varargs.h>
  127. X# endif
  128. X#endif
  129. X
  130. X#ifdef DEBUG
  131. XFILE *dfp;
  132. X#endif
  133. X
  134. X
  135. X#ifdef COPY_PASTE
  136. extern char *copybuffer;    /* def in mark.c jw. */
  137. extern copylen;
  138. X#endif /* COPY_PASTE */
  139. X
  140. extern char *blank, *null, Term[], screenterm[], **environ, *Termcap;
  141. int force_vt = 1, assume_LP = 0;
  142. extern int in_ovl;
  143. extern int ovl_blockfore;
  144. extern void (*ovl_process)();
  145. extern int help_page;
  146. extern int screenwidth, screenheight;
  147. extern int default_width, default_height;
  148. extern int Z0width, Z1width;
  149. extern int ISO2022;
  150. extern int status, HS;
  151. extern char *Z0, *WS, *LastMsg;
  152. extern time_t TimeDisplayed;
  153. int BellDisplayed;
  154. int VBellWait, MsgWait, MsgMinWait;
  155. X
  156. X/* tputs uses that: jw */
  157. extern short ospeed;
  158. X
  159. extern flowctl, wrap, visual_bell, default_monitor;
  160. extern int errno;
  161. extern sys_nerr;
  162. extern char *sys_errlist[];
  163. extern char mark_key_tab[];
  164. X
  165. X#ifdef TIOCGWINSZ
  166. extern struct winsize glwz;
  167. X#endif
  168. X
  169. static char *MakeWinMsg __P((char *, int));
  170. static void MakeNewEnv __P((void));
  171. static int Attach __P((int));
  172. static void Attacher __P((void));
  173. static void SigHandler __P((void));
  174. static sig_t SigChld __P(SIGPROTOARG);
  175. static sig_t SigInt __P(SIGPROTOARG);
  176. static sig_t CoreDump __P((int));
  177. static void DoWait __P((void));
  178. static sig_t Finit __P((int));
  179. static void InitKeytab __P((void));
  180. static void SetForeWindow __P((int));
  181. static int NextWindow __P((void));
  182. static int PreviousWindow __P((void));
  183. static int MoreWindows __P((void));
  184. static void FreeWindow __P((struct win *));
  185. static void execvpe __P((char *, char **, char **));
  186. static void LogToggle __P((void));
  187. static void ShowWindows __P((void));
  188. static void ShowTime __P((void));
  189. static void ShowInfo __P((void));
  190. static int OpenPTY __P((void));
  191. static void trysend __P((int, struct msg *, char *));
  192. X#if defined(SIGWINCH) && defined(TIOCGWINSZ)
  193. static sig_t SigAttWinch __P(SIGPROTOARG);
  194. X#endif
  195. static void fgtty __P((void));
  196. static void freetty __P((void));
  197. X#ifdef BSDJOBS
  198. static void brktty __P((void));
  199. X#endif
  200. X
  201. X#if defined(LOCK)
  202. static sig_t DoLock __P(SIGPROTOARG);
  203. static void LockTerminal __P((void));
  204. X#endif
  205. X
  206. X#ifdef COPY_PASTE
  207. static pastelen;
  208. static char *pastebuffer;
  209. X#endif
  210. X#ifdef PASSWORD
  211. extern char Password[];
  212. X#endif
  213. X
  214. static struct passwd *ppp;
  215. static char PtyName[32], TtyName[32];
  216. char *ShellProg;
  217. char *ShellArgs[2];
  218. static char inbuf[MAXWIN][IOSIZE];
  219. static inlen[MAXWIN];
  220. static inbuf_ct;
  221. static ESCseen;
  222. static GotSignal;
  223. X
  224. static char DefaultShell[] = "/bin/sh";
  225. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  226. X#if !(defined(sequent) || defined(_SEQUENT_) || defined(SVR4))
  227. static char PtyProto[] = "/dev/ptyXY";
  228. static char TtyProto[] = "/dev/ttyXY";
  229. X#endif
  230. int TtyMode = 0622;
  231. X#ifdef SOCKDIR
  232. char *SockDir = SOCKDIR;
  233. X#else
  234. char *SockDir = ".screen";
  235. X#endif
  236. extern char SockPath[], *SockNamePtr, *SockName;
  237. int ServerSocket = -1;
  238. static char **NewEnv;
  239. X
  240. char *RcFileName = NULL;
  241. char Esc = Ctrl('a');
  242. char MetaEsc = 'a';
  243. char *home;
  244. X
  245. int HasWindow;
  246. char *LoginName;
  247. char *BellString;
  248. char *VisualBellString;
  249. char *ActivityString;
  250. char *PowDetachString;
  251. int auto_detach = 1;
  252. int iflag, mflag, rflag, dflag, lsflag, quietflag, wipeflag;
  253. int adaptflag, loginflag = -1;
  254. static intrc, startc, stopc;
  255. char HostName[MAXSTR];
  256. int Detached, Suspended;
  257. int DeadlyMsg = 1;
  258. int AttacherPid;    /* Non-Zero in child if we have an attacher */
  259. int real_uid, real_gid, eff_uid, eff_gid;
  260. int default_histheight;
  261. int default_startup;
  262. int slowpaste;
  263. X
  264. X#if !defined(POSIX) && defined(BSDJOBS)
  265. int DevTty = -1;
  266. X#endif
  267. X
  268. X#ifdef NETHACK
  269. int nethackflag = 0;
  270. X#endif
  271. X
  272. struct mode OldMode, NewMode;
  273. X
  274. struct win *fore = NULL;
  275. int WinList = -1;
  276. int ForeNum;
  277. struct win *wtab[MAXWIN];
  278. X
  279. struct key ktab[256];
  280. X
  281. X#ifndef FD_SET
  282. typedef struct fd_set
  283. X{
  284. X  int fd_bits[1];
  285. X}      fd_set;
  286. X# define FD_ZERO(fd) ((fd)->fd_bits[0] = 0)
  287. X# define FD_SET(b,fd) ((fd)->fd_bits[0] |= 1 << (b))
  288. X# define FD_ISSET(b,fd) ((fd)->fd_bits[0] & 1 << (b))
  289. X# define FD_SETSIZE 32
  290. X#endif
  291. X
  292. X
  293. X#ifndef WTERMSIG
  294. X# ifndef BSDWAIT /* if wait is NOT a union: */
  295. X#  define WTERMSIG(status) (status & 0177)
  296. X# else
  297. X#  define WTERMSIG(status) status.w_T.w_Termsig 
  298. X# endif
  299. X#endif
  300. X
  301. X#ifndef WIFCORESIG
  302. X# ifndef BSDWAIT /* if wait is NOT a union: */
  303. X#  define WIFCORESIG(status) (status & 0200)
  304. X# else
  305. X#  define WIFCORESIG(status) status.w_T.w_Coredump
  306. X# endif
  307. X#endif
  308. X
  309. X#ifndef WEXITSTATUS
  310. X# ifndef BSDWAIT /* if wait is NOT a union: */
  311. X#  define WEXITSTATUS(status) ((status >> 8) & 0377)
  312. X# else
  313. X#  define WEXITSTATUS(status) status.w_T.w_Retcode
  314. X# endif
  315. X#endif
  316. X
  317. char *shellaka = NULL;
  318. X
  319. X/*
  320. X * Do this last
  321. X */
  322. X#include "extern.h"
  323. X
  324. X/*
  325. X * XXX: Missing system header files.
  326. X */
  327. X#ifdef USEVARARGS
  328. X#ifdef SVR4
  329. int vsprintf __P((char *, const char *, va_list));
  330. X#else
  331. int vsprintf __P((char *, char *, va_list));
  332. X#endif
  333. X#endif
  334. int select __P((int, fd_set *, fd_set *, fd_set *, struct timeval *));
  335. X
  336. X#ifdef BSDJOBS
  337. static void
  338. brktty()
  339. X{
  340. X# ifdef POSIX
  341. X  setsid();        /* will break terminal affilition */
  342. X# else
  343. X  if (DevTty)
  344. X    if (ioctl(DevTty, TIOCNOTTY, (char *) 0) != 0)
  345. X      debug2("brktty: ioctl(DevTty=%d, TIOCNOTTY, 0) = %d\n", DevTty, errno);
  346. X# endif
  347. X}
  348. X#endif
  349. X
  350. static void
  351. freetty()
  352. X{
  353. X#ifdef BSDJOBS
  354. X  brktty();
  355. X# ifndef POSIX
  356. X  if (DevTty >= 0)
  357. X    {
  358. X      close(DevTty);
  359. X      DevTty = -1;
  360. X    }
  361. X# endif
  362. X#endif
  363. X  close(0);
  364. X  close(1);
  365. X  close(2);
  366. X}
  367. X
  368. static void
  369. fgtty()
  370. X{
  371. X#ifdef BSDJOBS
  372. X  int mypid;
  373. X
  374. X  mypid = getpid();
  375. X# ifdef POSIX
  376. X  if (tcsetpgrp(0, mypid))
  377. X# else
  378. X  if (ioctl(0, TIOCSPGRP, &mypid) != 0)
  379. X# endif
  380. X    debug1("fgtty: tcsetpgrp: %d\n", errno);
  381. X# ifdef POSIX
  382. X#  ifdef SVR4
  383. X  if (getpgid(0) != mypid)
  384. X#   endif
  385. X  if (setpgid(0, mypid))
  386. X# else
  387. X  if (setpgrp(0, mypid))
  388. X# endif
  389. X    debug1("fgtty: setpgid: %d\n", errno);
  390. X#endif
  391. X}
  392. X
  393. X#ifdef hpux
  394. X/*
  395. X * hpux has berkeley signal semantics if we use sigvector,
  396. X * but not, if we use signal, so we define our own signal() routine.
  397. X * (jw)
  398. X */
  399. void (*signal(sig, func)) ()
  400. int sig;
  401. void (*func) ();
  402. X{
  403. X  struct sigvec osv, sv;
  404. X
  405. X  sv.sv_handler = func;
  406. X  sv.sv_mask = sigmask(sig);
  407. X  sv.sv_flags = SV_BSDSIG;
  408. X  if (sigvector(sig, &sv, &osv) < 0)
  409. X    return (BADSIG);
  410. X  return (osv.sv_handler);
  411. X}
  412. X#endif    /* hpux */
  413. X
  414. X#ifndef USEBCOPY
  415. void bcopy(s1, s2, len)
  416. register char *s1, *s2;
  417. register int len;
  418. X{
  419. X  if (s1 < s2 && s2 < s1 + len)
  420. X    {
  421. X      s1 += len;
  422. X      s2 += len;
  423. X      while (len-- > 0)
  424. X    *--s2 = *--s1;
  425. X    }
  426. X  else
  427. X    while (len-- > 0)
  428. X      *s2++ = *s1++;
  429. X}
  430. X#endif    /* USEBCOPY */
  431. X
  432. void bclear(p, n)
  433. int n;
  434. char *p;
  435. X{
  436. X  bcopy(blank, p, n);
  437. X}
  438. X
  439. void main(ac, av)
  440. int ac;
  441. char **av;
  442. X{
  443. X  register int n, len;
  444. X  register struct win *p;
  445. X  char *ap, *aka = NULL;
  446. X  char *av0;
  447. X  int s = 0;
  448. X  fd_set r, w;
  449. X  int aflag = 0;
  450. X  struct timeval tv;
  451. X  int nsel;
  452. X  char buf[IOSIZE], *bufp, *myname = (ac == 0) ? "screen" : av[0];
  453. X  struct stat st;
  454. X  int buflen, tmp;
  455. X#ifdef _MODE_T            /* (jw) */
  456. X  mode_t oumask;
  457. X#else
  458. X  int oumask;
  459. X#endif
  460. X#ifdef SYSV
  461. X  struct utsname utsnam;
  462. X#endif
  463. X
  464. X/*
  465. X *  First, close all unused descriptors
  466. X *  (otherwise, we might have problems with the select() call)
  467. X */
  468. X#ifdef SYSV
  469. X  for (n = NOFILE - 1; n > 2; n--)
  470. X    close(n);
  471. X#else
  472. X  for (n = getdtablesize() - 1; n > 2; n--)
  473. X    close(n);
  474. X#endif
  475. X#ifdef DEBUG
  476. X  (void) mkdir("/tmp/debug", 0777);
  477. X  if ((dfp = fopen("/tmp/debug/screen.front", "w")) == NULL)
  478. X    dfp = stderr;
  479. X  else
  480. X    (void) chmod("/tmp/debug/screen.front", 0666);
  481. X#endif
  482. X  debug1("-- screen debug started %s\n", *av);
  483. X#ifdef POSIX
  484. X  debug("POSIX\n");
  485. X#endif
  486. X#ifdef TERMIO
  487. X  debug("TERMIO\n");
  488. X#endif
  489. X#ifdef SYSV
  490. X  debug("SYSV\n");
  491. X#endif
  492. X#ifdef NAMEDPIPE
  493. X  debug("NAMEDPIPE\n");
  494. X#endif
  495. X#if defined(SIGWINCH) && defined(TIOCGWINSZ)
  496. X  debug("Window changing enabled\n");
  497. X#endif
  498. X#ifdef NOREUID
  499. X  debug("NOREUID\n");
  500. X#endif
  501. X#ifdef hpux
  502. X  debug("hpux\n");
  503. X#endif
  504. X#ifdef USEBCOPY
  505. X  debug("USEBCOPY\n");
  506. X#endif
  507. X#ifdef UTMPOK
  508. X  debug("UTMPOK\n");
  509. X#endif
  510. X#ifdef LOADAV
  511. X  debug("LOADAV\n");
  512. X#endif
  513. X#ifdef NETHACK
  514. X  debug("NETHACK\n");
  515. X#endif
  516. X#ifdef TERMINFO
  517. X  debug("TERMINFO\n");
  518. X#endif
  519. X
  520. X  BellString = SaveStr("Bell in window %");
  521. X  VisualBellString = SaveStr("   Wuff,  Wuff!!  ");
  522. X  ActivityString = SaveStr("Activity in window %");
  523. X  PowDetachString = 0;
  524. X  default_histheight = DEFAULTHISTHEIGHT;
  525. X  default_startup = (ac > 1) ? 0 : 1;
  526. X  adaptflag = 0;
  527. X  slowpaste = 0;
  528. X  VBellWait = VBELLWAIT;
  529. X  MsgWait = MSGWAIT;
  530. X  MsgMinWait = MSGMINWAIT;
  531. X  CompileKeys(NULL, mark_key_tab);
  532. X
  533. X  av0 = *av;
  534. X  while (ac > 0)
  535. X    {
  536. X      ap = *++av;
  537. X      if (--ac > 0 && *ap == '-')
  538. X    {
  539. X      switch (ap[1])
  540. X        {
  541. X        case 'a':
  542. X          aflag = 1;
  543. X          break;
  544. X        case 'A':
  545. X          adaptflag = 1;
  546. X          break;
  547. X        case 'c':
  548. X          if (ap[2])
  549. X        RcFileName = ap + 2;
  550. X          else
  551. X        {
  552. X          if (--ac == 0)
  553. X            exit_with_usage(myname);
  554. X          RcFileName = *++av;
  555. X        }
  556. X          break;
  557. X        case 'e':
  558. X          if (ap[2])
  559. X        ap += 2;
  560. X          else
  561. X        {
  562. X          if (--ac == 0)
  563. X            exit_with_usage(myname);
  564. X          ap = *++av;
  565. X        }
  566. X          if (!ParseEscape(ap))
  567. X        Msg(0, "Two characters are required with -e option.");
  568. X          break;
  569. X        case 'f':
  570. X          switch (ap[2])
  571. X        {
  572. X        case 'n':
  573. X        case '0':
  574. X          flowctl = 1;
  575. X          break;
  576. X        case 'y':
  577. X        case '1':
  578. X        case '\0':
  579. X          flowctl = 2;
  580. X          break;
  581. X        case 'a':
  582. X          flowctl = 3;
  583. X          break;
  584. X        default:
  585. X          exit_with_usage(myname);
  586. X        }
  587. X          break;
  588. X            case 'h':
  589. X          if (ap[2])
  590. X        default_histheight = atoi(ap + 2);
  591. X          else
  592. X        {
  593. X          if (--ac == 0)
  594. X            exit_with_usage(myname);
  595. X          default_histheight = atoi(*++av);
  596. X        }
  597. X          if (default_histheight < 0)
  598. X        default_histheight = 0;
  599. X          break;
  600. X        case 'i':
  601. X          iflag = 1;
  602. X          break;
  603. X        case 't': /* title is a synonym for AkA */
  604. X        case 'k':
  605. X          if (ap[2])
  606. X        aka = ap + 2;
  607. X          else
  608. X        {
  609. X          if (--ac == 0)
  610. X            exit_with_usage(myname);
  611. X          aka = *++av;
  612. X        }
  613. X          break;
  614. X        case 'l':
  615. X          switch (ap[2])
  616. X        {
  617. X        case 'n':
  618. X        case '0':
  619. X          loginflag = 0;
  620. X          break;
  621. X        case 'y':
  622. X        case '1':
  623. X        case '\0':
  624. X          loginflag = 1;
  625. X          break;
  626. X        case 's':
  627. X        case 'i':
  628. X          lsflag = 1;
  629. X          break;
  630. X        default:
  631. X          exit_with_usage(myname);
  632. X        }
  633. X          break;
  634. X        case 'w':
  635. X          lsflag = 1;
  636. X          wipeflag = 1;
  637. X          break;
  638. X        case 'L':
  639. X          assume_LP = 1;
  640. X          break;
  641. X        case 'm':
  642. X          mflag = 1;
  643. X          break;
  644. X        case 'O':
  645. X          force_vt = 0;
  646. X          break;
  647. X        case 'T':
  648. X              if (ap[2])
  649. X        {
  650. X          if ((unsigned)strlen(ap+2) < 20)
  651. X                    strcpy(screenterm, ap + 2);
  652. X        }
  653. X              else
  654. X                {
  655. X                  if (--ac == 0)
  656. X                    exit_with_usage(myname);
  657. X          if ((unsigned)strlen(*++av) < 20)
  658. X                    strcpy(screenterm, *av);
  659. X                }
  660. X              break;
  661. X        case 'q':
  662. X          quietflag = 1;
  663. X          break;
  664. X        case 'r':
  665. X          if (ap[2])
  666. X        {
  667. X          SockName = ap + 2;
  668. X          if (ac != 1)
  669. X            exit_with_usage(myname);
  670. X        }
  671. X          else if (--ac == 1)
  672. X        {
  673. X          if (*av[1] != '-')
  674. X            SockName = *++av;
  675. X        }
  676. X          else if (ac != 0)
  677. X        exit_with_usage(myname);
  678. X          rflag = 1;
  679. X          break;
  680. X        case 'R':
  681. X          rflag = 2;
  682. X          break;
  683. X#ifdef REMOTE_DETACH
  684. X        case 'd':
  685. X          dflag = 1;
  686. X          /* FALLTHRU */
  687. X        case 'D':
  688. X          if (!dflag)
  689. X        dflag = 2;
  690. X          if (ap[2])
  691. X        SockName = ap + 2;
  692. X          if (ac == 2)
  693. X        {
  694. X          if (*av[1] != '-')
  695. X            {
  696. X              SockName = *++av;
  697. X              ac--;
  698. X            }
  699. X        }
  700. X          break;
  701. X#endif
  702. X        case 's':
  703. X          if (ap[2])
  704. X        ShellProg = ap + 2;
  705. X          else
  706. X        {
  707. X          if (--ac == 0)
  708. X            exit_with_usage(myname);
  709. X          ShellProg = *++av;
  710. X        }
  711. X          break;
  712. X        default:
  713. X          exit_with_usage(myname);
  714. X        }
  715. X    }
  716. X      else
  717. X    break;
  718. X    }
  719. X  real_uid = getuid();
  720. X  real_gid = getgid();
  721. X  eff_uid = geteuid();
  722. X  eff_gid = getegid();
  723. X  if (!ShellProg && (ShellProg = getenv("SHELL")) == 0)
  724. X    ShellProg = DefaultShell;
  725. X  ShellArgs[0] = ShellProg;
  726. X#ifdef NETHACK
  727. X  nethackflag = (getenv("NETHACKOPTIONS") != NULL);
  728. X#endif
  729. X  home = getenv("HOME");    /* may or may not return a result. jw. */
  730. X  if ((LoginName = getlogin()) == 0 || LoginName[0] == '\0')
  731. X    {
  732. X      if ((ppp = getpwuid(real_uid)) == 0)
  733. X        {
  734. X#ifdef NETHACK
  735. X          if (nethackflag)
  736. X        Msg(0, "An alarm sounds through the dungeon...\nWarning, the kops are coming.");
  737. X      else
  738. X#endif
  739. X      Msg(0, "getpwuid() can't identify your account!");
  740. X      exit(1);
  741. X        }
  742. X      LoginName = ppp->pw_name;
  743. X    }
  744. X  /* is anyone cheating? jw. */
  745. X  if (((ppp != (struct passwd *) 0) && (LoginName == ppp->pw_name)) ||
  746. X      ((ppp = getpwnam(LoginName)) != (struct passwd *) 0))
  747. X    {
  748. X      if (ppp->pw_uid != real_uid)
  749. X    {
  750. X#ifdef NETHACK
  751. X          if (nethackflag)
  752. X        Msg(0, "You cannot resist to mimic a pile of gold.\nThe system ignores you.");
  753. X      else
  754. X#endif
  755. X      Msg(0, "getuid() and pw_uid don't match!");
  756. X      exit(1);
  757. X    }
  758. X    }
  759. X  else
  760. X    {
  761. X#ifdef NETHACK
  762. X      if (nethackflag)
  763. X        Msg(0, "An alarm sounds through the dungeon...\nWarning, the kops are after you.");
  764. X      else
  765. X#endif
  766. X      Msg(0, "getpwnam() can't identify your account!");
  767. X      exit(1);
  768. X    }
  769. X  if (home == 0 || *home == '\0')
  770. X    home = ppp->pw_dir;
  771. X  if ((unsigned)strlen(LoginName) > 20)
  772. X    Msg(0, "LoginName too long - sorry.");
  773. X  if ((unsigned)strlen(home) > MAXPATH - 25)
  774. X    Msg(0, "$HOME too long - sorry.");
  775. X#ifdef PASSWORD
  776. X  strcpy(Password, ppp->pw_passwd);
  777. X#endif
  778. X
  779. X  if (!isatty(0))
  780. X    {
  781. X#ifdef NETHACK
  782. X      if (nethackflag)
  783. X    Msg(0, "You must play from a terminal.");
  784. X      else
  785. X#endif
  786. X      Msg(0, "Must be connected to a terminal.");
  787. X      exit(1);
  788. X    }
  789. X#ifdef _MODE_T
  790. X  oumask = umask(0);        /* well, unsigned never fails? jw. */
  791. X#else
  792. X  if ((oumask = umask(0)) == -1)
  793. X    Msg(errno, "Cannot change umask to zero");
  794. X#endif
  795. X  if ((SockDir = getenv("ISCREENDIR")) == NULL)
  796. X    SockDir = getenv("SCREENDIR");
  797. X  if (SockDir && (unsigned)strlen(SockDir) >= MAXPATH - 1)
  798. X    Msg(0, "ridiculous long $(I)SCREENDIR - try again.");
  799. X#ifndef SOCKDIR
  800. X  if (SockDir == 0)
  801. X    {
  802. X      sprintf(SockPath, "%s/.screen", home);
  803. X      SockDir = SockPath;
  804. X    }
  805. X#endif
  806. X  if (SockDir)
  807. X    {
  808. X      if (access(SockDir, F_OK))
  809. X    {
  810. X      if (UserContext() > 0)
  811. X        {
  812. X          if (mkdir(SockDir, 0700))
  813. X        UserReturn(0);
  814. X          UserReturn(1);
  815. X        }
  816. X      if (UserStatus() <= 0)
  817. X        Msg(0, "Cannot make directory '%s'", SockDir);
  818. X    }
  819. X      if (SockDir != SockPath)
  820. X        strcpy(SockPath, SockDir);
  821. X    }
  822. X#ifdef SOCKDIR
  823. X  else
  824. X    {
  825. X      SockDir = SOCKDIR;
  826. X      if (stat(SockDir, &st))
  827. X    {
  828. X      if (mkdir(SockDir, eff_uid ? 0777 : 0755) == -1)
  829. X        Msg(errno, "Cannot make directory '%s'", SockDir);
  830. X    }
  831. X      else
  832. X    {
  833. X          n = eff_uid ? 0777 : 0755;
  834. X      if ((st.st_mode & 0777) != n)
  835. X        Msg(0, "Directory '%s' must have mode %03o.", SockDir, n);
  836. X    }
  837. X      sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
  838. X      if (access(SockPath, F_OK))
  839. X    {
  840. X      if (mkdir(SockPath, 0700) == -1)
  841. X        Msg(errno, "Cannot make directory '%s'", SockPath);
  842. X      (void) chown(SockPath, real_uid, real_gid);
  843. X    }
  844. X    }
  845. X#endif
  846. X  if (stat(SockPath, &st) == -1)
  847. X    {
  848. X      Msg(errno, "Cannot access %s", SockPath);
  849. X    }
  850. X  else
  851. X    {
  852. X      if ((st.st_mode & S_IFMT) != S_IFDIR)
  853. X    Msg(0, "%s is not a directory.", SockPath);
  854. X      if (st.st_uid != real_uid)
  855. X    Msg(0, "You are not the owner of %s.", SockPath);
  856. X      if ((st.st_mode & 0777) != 0700)
  857. X    Msg(0, "Directory %s must have mode 700.", SockPath);
  858. X    }
  859. X  strcat(SockPath, "/");
  860. X  SockNamePtr = SockPath + strlen(SockPath);
  861. X  (void) umask(oumask);
  862. X#ifdef SYSV
  863. X  if (uname(&utsnam) == -1)
  864. X    Msg(0, "uname() failed, errno = %d", errno);
  865. X  else
  866. X    {
  867. X      strncpy(HostName, utsnam.nodename, MAXSTR);
  868. X      HostName[(sizeof(utsnam.nodename) <= MAXSTR) ? 
  869. X               sizeof(utsnam.nodename) : MAXSTR] = '\0';
  870. X    }
  871. X#else
  872. X  (void) gethostname(HostName, MAXSTR);
  873. X#endif
  874. X  HostName[MAXSTR - 1] = '\0';
  875. X  if ((ap = index(HostName, '.')) != NULL)
  876. X    *ap = '\0';
  877. X  GetTTY(0, &OldMode);
  878. X#ifdef POSIX
  879. X  ospeed = (short) cfgetospeed(&OldMode.tio);
  880. X#else
  881. X# ifndef TERMIO
  882. X  ospeed = (short) OldMode.m_ttyb.sg_ospeed;
  883. X# endif
  884. X#endif
  885. X  debug1("...setting extern short ospeed = %d\n", ospeed);
  886. X
  887. X  if (lsflag)
  888. X    {
  889. X      int i;
  890. X      i = FindSocket(0, NULL);
  891. X      /* MakeClientSocket appended the last SockName there: */
  892. X      *SockNamePtr = '\0';
  893. X      if (i == 0)
  894. X    {
  895. X#ifdef NETHACK
  896. X          if (nethackflag)
  897. X        Msg(0, "This room is empty (%s)\n", SockPath);
  898. X          else
  899. X#endif                /* NETHACK */
  900. X          Msg(0, "No Sockets found in %s\n", SockPath);
  901. X        }
  902. X      else
  903. X        Msg(0, "%d Socket%s in %s.\n", i, i > 1 ? "s" : "", SockPath);
  904. X        /* NOTREACHED */
  905. X    }
  906. X  if (rflag)
  907. X    {
  908. X      debug("screen -r: - is there anybody out there?\n");
  909. X      if (Attach(MSG_ATTACH))
  910. X    {
  911. X      Attacher();
  912. X      /* NOTREACHED */
  913. X    }
  914. X      debug("screen -r: backend not responding -- still crying\n");
  915. X    }
  916. X  else if (dflag)
  917. X    {
  918. X      (void) Attach(MSG_DETACH);
  919. X      DeadlyMsg = 0;
  920. X      Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
  921. X      eexit(0);
  922. X      /* NOTREACHED */
  923. X    }
  924. X  if (GetSockName())
  925. X    {
  926. X      s = MakeClientSocket(1, SockName);
  927. X      if (ac == 0)
  928. X    {
  929. X      ac = 1;
  930. X      av = ShellArgs;
  931. X    }
  932. X      av[ac] = aka;
  933. X      SendCreateMsg(s, ac, av, aflag, flowctl, loginflag, default_histheight,
  934. X            screenterm);
  935. X      close(s);
  936. X      exit(0);
  937. X    }
  938. X#if !defined(POSIX) && defined(BSDJOBS)
  939. X  if ((DevTty = open("/dev/tty", O_RDWR | O_NDELAY)) == -1)
  940. X    Msg(errno, "/dev/tty");
  941. X#endif
  942. X  switch (fork())
  943. X    {
  944. X    case -1:
  945. X      Msg(errno, "fork");
  946. X      /* NOTREACHED */
  947. X    case 0:
  948. X      break;
  949. X    default:
  950. X      Attacher();
  951. X      /* NOTREACHED */
  952. X    }
  953. X#ifdef DEBUG
  954. X  if (dfp != stderr)
  955. X    fclose(dfp);
  956. X  if ((dfp = fopen("/tmp/debug/screen.back", "w")) == NULL)
  957. X    dfp = stderr;
  958. X  else
  959. X    (void) chmod("/tmp/debug/screen.back", 0666);
  960. X#endif
  961. X  debug("-- screen.back debug started\n");
  962. X  ap = av0 + strlen(av0) - 1;
  963. X  while (ap >= av0)
  964. X    {
  965. X      if (!strncmp("screen", ap, 6))
  966. X    {
  967. X      strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
  968. X      break;
  969. X    }
  970. X      ap--;
  971. X    }
  972. X  if (ap < av0)
  973. X    *av0 = 'S';
  974. X
  975. X  AttacherPid = getppid();
  976. X  ServerSocket = s = MakeServerSocket();
  977. X#ifdef ETCSCREENRC
  978. X  if ((ap = getenv("SYSSCREENRC")) == NULL)
  979. X    StartRc(ETCSCREENRC);
  980. X  else
  981. X    StartRc(ap);
  982. X#endif
  983. X  StartRc(RcFileName);
  984. X  InitTermcap();
  985. X  InitTerm(0);
  986. X  MakeNewEnv();
  987. X#ifdef UTMPOK
  988. X  InitUtmp();
  989. X#endif
  990. X#ifdef LOADAV
  991. X  InitKmem();
  992. X#endif
  993. X  signal(SIGHUP, SigHup);
  994. X  signal(SIGINT, Finit);
  995. X  signal(SIGQUIT, Finit);
  996. X  signal(SIGTERM, Finit);
  997. X#ifdef BSDJOBS
  998. X  signal(SIGTTIN, SIG_IGN);
  999. X  signal(SIGTTOU, SIG_IGN);
  1000. X#endif
  1001. X  if (eff_uid != real_uid)
  1002. X    {        
  1003. X      /* if running with s-bit, we must install a special signal
  1004. X       * handler routine that resets the s-bit, so that we get a
  1005. X       * core file anyway.
  1006. X       */
  1007. X      signal(SIGBUS, CoreDump);
  1008. X      signal(SIGSEGV, CoreDump);
  1009. X    }
  1010. X  InitKeytab();
  1011. X#ifdef ETCSCREENRC
  1012. X  if ((ap = getenv("SYSSCREENRC")) == NULL)
  1013. X    FinishRc(ETCSCREENRC);
  1014. X  else
  1015. X    FinishRc(ap);
  1016. X#endif
  1017. X  FinishRc(RcFileName);
  1018. X  SetMode(&OldMode, &NewMode);
  1019. X  SetTTY(0, &NewMode);
  1020. X  if (loginflag == -1)
  1021. X      loginflag = LOGINDEFAULT;
  1022. X  if (ac == 0)
  1023. X    {
  1024. X      ac = 1;
  1025. X      av = ShellArgs;
  1026. X      if (!aka)
  1027. X    aka = shellaka;
  1028. X    }
  1029. X  if (!HasWindow)
  1030. X    {
  1031. X      debug("We open one default window, as screenrc did not specify one.\n");
  1032. X      if (MakeWindow(aka, av, aflag, flowctl, 0, (char *) 0, loginflag, -1, 0) == -1)
  1033. X    {
  1034. X      Finit(1);
  1035. X      /* NOTREACHED */
  1036. X    }
  1037. X    }
  1038. X  if (default_startup)
  1039. X    display_copyright();
  1040. X#ifdef SYSV
  1041. X  signal(SIGCLD, SigChld);
  1042. X#else
  1043. X  signal(SIGCHLD, SigChld);
  1044. X#endif
  1045. X  signal(SIGINT, SigInt);
  1046. X  tv.tv_usec = 0;
  1047. X  if (rflag == 2)
  1048. X    {
  1049. X#ifdef NETHACK
  1050. X      if (nethackflag)
  1051. X        Msg(0, "I can't seem to find a... Hey, wait a minute!  Here comes a screen now.");
  1052. X      else
  1053. X#endif
  1054. X      Msg(0, "New screen...");
  1055. X      rflag = 0;
  1056. X    }
  1057. X#ifdef BSDJOBS
  1058. X  brktty();
  1059. X#endif
  1060. X  for (;;)
  1061. X    {
  1062. X      /*
  1063. X       * check to see if message line should be removed
  1064. X       */
  1065. X      if (status)
  1066. X    {
  1067. X      int time_left;
  1068. X
  1069. X      debug("checking status...\n");
  1070. X      time_left = TimeDisplayed + (BellDisplayed ? VBellWait : MsgWait) - time((time_t *)0);
  1071. X      if (time_left > 0)
  1072. X        {
  1073. X          tv.tv_sec = time_left;
  1074. X          debug(" not yet.\n");
  1075. X        }
  1076. X      else
  1077. X        {
  1078. X          debug(" removing now.\n");
  1079. X          RemoveStatus();
  1080. X        }
  1081. X    }
  1082. X      /*
  1083. X       * check for I/O on all available I/O descriptors
  1084. X       */
  1085. X      FD_ZERO(&r);
  1086. X      FD_ZERO(&w);
  1087. X      if (inbuf_ct > 0)
  1088. X    for (n = 0; n < MAXWIN; n++)
  1089. X#ifdef COPY_PASTE        /* wrong here? jw. */
  1090. X      if (inlen[n] > 0 || (pastelen > 0 && n == ForeNum))
  1091. X#else
  1092. X      if (inlen[n] > 0)
  1093. X#endif
  1094. X        FD_SET(wtab[n]->ptyfd, &w);
  1095. X      if (!Detached)
  1096. X    FD_SET(0, &r);
  1097. X      for (n = WinList; n != -1; n = p->WinLink)
  1098. X    {
  1099. X      p = wtab[n];
  1100. X      if (p->active && status && !BellDisplayed && !HS)
  1101. X        continue;
  1102. X      if (p->outlen > 0)
  1103. X        continue;
  1104. X      if (in_ovl && ovl_blockfore && n == ForeNum)
  1105. X        continue;
  1106. X      FD_SET(p->ptyfd, &r);
  1107. X    }
  1108. X      FD_SET(s, &r);
  1109. X      (void) fflush(stdout);
  1110. X      if (GotSignal && !status)
  1111. X    {
  1112. X      SigHandler();
  1113. X      continue;
  1114. X    }
  1115. X      if ((nsel = select(FD_SETSIZE, &r, &w, 0, status ? &tv : (struct timeval *) 0)) < 0)
  1116. X    {
  1117. X      debug1("Bad select - errno %d\n",errno);
  1118. X      if (errno == EINTR)
  1119. X        {
  1120. X          errno = 0;
  1121. X          continue;
  1122. X        }
  1123. X      perror("select");
  1124. X      Finit(1);
  1125. X      /* NOTREACHED */
  1126. X    }
  1127. X      if (GotSignal && !status)
  1128. X    {
  1129. X      SigHandler();
  1130. X      continue;
  1131. X    }
  1132. X      /* Process a client connect attempt and message */
  1133. X      if (nsel && FD_ISSET(s, &r))
  1134. X    {
  1135. X          nsel--;
  1136. X      if (!HS)
  1137. X        RemoveStatus();
  1138. X      if (in_ovl)
  1139. X        {
  1140. X          SetOvlCurr();
  1141. X          (*ovl_process)(0,0); /* We have to abort first!! */
  1142. X          CheckScreenSize(1); /* Change fore */
  1143. X#ifdef NETHACK
  1144. X              if (nethackflag)
  1145. X            Msg(0, "KAABLAMM!!!  You triggered a land mine!");
  1146. X              else
  1147. X#endif
  1148. X          Msg(0, "Aborted because of window change or message.");
  1149. X        }
  1150. X      else
  1151. X        CheckScreenSize(1); /* Change fore */
  1152. X      ReceiveMsg(s);
  1153. X      continue;
  1154. X    }
  1155. X      /* Read, process, and store the user input */
  1156. X      if (nsel && FD_ISSET(0, &r))
  1157. X    {
  1158. X          nsel--;
  1159. X      if (!HS)
  1160. X        RemoveStatus();
  1161. X      if (ESCseen)
  1162. X        {
  1163. X          buf[0] = Esc;
  1164. X          buflen = read(0, buf + 1, IOSIZE - 1) + 1;
  1165. X          ESCseen = 0;
  1166. X        }
  1167. X      else
  1168. X        buflen = read(0, buf, IOSIZE);
  1169. X      if (buflen < 0)
  1170. X        {
  1171. X          debug1("Read error: %d - SigHup()ing!\n", errno);
  1172. X          SigHup(SIGARG);
  1173. X          continue;
  1174. X        }
  1175. X      if (buflen == 0)
  1176. X        {
  1177. X          debug("Found EOF - SigHup()ing!\n");
  1178. X          SigHup(SIGARG);
  1179. X          continue;
  1180. X        }
  1181. X      bufp = buf;
  1182. X          if (in_ovl)
  1183. X        {
  1184. X          SetOvlCurr();
  1185. X          (*ovl_process)(&bufp, &buflen);
  1186. X        }
  1187. X      while (buflen > 0)
  1188. X        {
  1189. X          n = ForeNum;
  1190. X          len = inlen[n];
  1191. X          bufp = ProcessInput(bufp, &buflen, inbuf[n], &inlen[n],
  1192. X                  sizeof *inbuf);
  1193. X          if (inlen[n] > 0 && len == 0)
  1194. X        inbuf_ct++;
  1195. X        }
  1196. X      if (inbuf_ct > 0)
  1197. X        continue;
  1198. X    }
  1199. X      if (GotSignal && !status)
  1200. X    {
  1201. X      SigHandler();
  1202. X      continue;
  1203. X    }
  1204. X#ifdef COPY_PASTE
  1205. X      /* Write the copybuffer contents first, if any. jw. */
  1206. X      if (pastelen > 0)
  1207. X    {
  1208. X      n = ForeNum;
  1209. X      debug1("writing pastebuffer (%d)\n", pastelen);
  1210. X      tmp = wtab[n]->ptyfd;
  1211. X      if (            /* FD_ISSET(tmp,&w) && */
  1212. X          (len = write(tmp, pastebuffer,
  1213. X               pastelen > IOSIZE ? IOSIZE : pastelen)) > 0)
  1214. X        {
  1215. X          pastebuffer += len;
  1216. X          pastelen -= len;
  1217. X          debug1("%d bytes pasted\n", len);
  1218. X          if (slowpaste > 0)
  1219. X        {
  1220. X          struct timeval t;
  1221. X
  1222. X                  debug1("slowpaste %d\n", slowpaste);
  1223. X          t.tv_usec = (long) (slowpaste * 1000);
  1224. X          t.tv_sec = 0;
  1225. X          select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
  1226. X        }
  1227. X          else
  1228. X            continue;
  1229. X        }
  1230. X      /* 
  1231. X       * we have to go further down, process some output, if 
  1232. X       * no bytes were written...
  1233. X       */
  1234. X    }
  1235. X#endif
  1236. X      /* Write the stored user input to the window descriptors */
  1237. X      if ( nsel && inbuf_ct > 0)
  1238. X    {
  1239. X      for (n = 0; n < MAXWIN ; n++)
  1240. X        {
  1241. X          if (inlen[n] <= 0 )
  1242. X        continue;
  1243. X          tmp = wtab[n]->ptyfd;
  1244. X              if (FD_ISSET(tmp,&w))
  1245. X                {
  1246. X          if ( (len = write(tmp, inbuf[n], inlen[n])) > 0)
  1247. X            {
  1248. X              if ((inlen[n] -= len) == 0)
  1249. X              inbuf_ct--;
  1250. X              bcopy(inbuf[n] + len, inbuf[n], inlen[n]);
  1251. X            }
  1252. X          if (--nsel == 0)
  1253. X            break;
  1254. X        }
  1255. X        }
  1256. X    }
  1257. X      if (GotSignal && !status)
  1258. X    {
  1259. X      SigHandler();
  1260. X      continue;
  1261. X    }
  1262. X      /* Read and process the output from the window descriptors */
  1263. X      for (n = WinList; n != -1; n = p->WinLink)
  1264. X    {
  1265. X      p = wtab[n];
  1266. X      if (in_ovl && ovl_blockfore && n == ForeNum)
  1267. X        continue;
  1268. X      if (p->outlen)
  1269. X        WriteString(p, p->outbuf, p->outlen);
  1270. X      else if (nsel && FD_ISSET(p->ptyfd, &r))
  1271. X        {
  1272. X          nsel--;
  1273. X          if ((len = read(p->ptyfd, buf, IOSIZE)) == -1)
  1274. X        {
  1275. X#ifdef EWOULDBLOCK
  1276. X          if (errno == EWOULDBLOCK)
  1277. X            len = 0;
  1278. X#endif
  1279. X        }
  1280. X          if (len > 0)
  1281. X        WriteString(p, buf, len);
  1282. X        }
  1283. X      if (p->bell == BELL_ON)
  1284. X        {
  1285. X          p->bell = BELL_DONE;
  1286. X          Msg(0, MakeWinMsg(BellString, n));
  1287. X          if (p->monitor == MON_FOUND)
  1288. X        p->monitor = MON_DONE;
  1289. X        }
  1290. X      else if (p->bell == BELL_VISUAL)
  1291. X        {
  1292. X          if (!BellDisplayed)
  1293. X        {
  1294. X          p->bell = BELL_DONE;
  1295. X          Msg(0, VisualBellString);
  1296. X          BellDisplayed = 1;
  1297. X        }
  1298. X        }
  1299. X      else if (p->monitor == MON_FOUND)
  1300. X        {
  1301. X          p->monitor = MON_DONE;
  1302. X          Msg(0, MakeWinMsg(ActivityString, n));
  1303. X        }
  1304. X    }
  1305. X      if (GotSignal && !status)
  1306. X    SigHandler();
  1307. X#ifdef DEBUG
  1308. X      if (nsel)
  1309. X    debug1("Left over nsel: %d\n",nsel);
  1310. X#endif
  1311. X    }
  1312. X  /* NOTREACHED */
  1313. X}
  1314. X
  1315. static void SigHandler()
  1316. X{
  1317. X  struct stat st;
  1318. X  while (GotSignal)
  1319. X    {
  1320. X      GotSignal = 0;
  1321. X      DoWait();
  1322. X#ifdef SYSV
  1323. X      signal(SIGCLD, SigChld);
  1324. X#endif
  1325. X    }
  1326. X  if (stat(SockPath, &st) == -1)
  1327. X    {
  1328. X      debug1("SigHandler: Yuck! cannot stat '%s'\n", SockPath);
  1329. X      if (!RecoverSocket())
  1330. X    {
  1331. X      debug("SCREEN cannot recover from corrupt Socket,bye\n");
  1332. X      Finit(1);
  1333. X    }
  1334. X      else
  1335. X    debug1("'%s' reconstructed\n", SockPath);
  1336. X    }
  1337. X  else
  1338. X    debug2("SigHandler: stat '%s' o.k. (%03o)\n", SockPath, st.st_mode);
  1339. X}
  1340. X
  1341. X#ifdef DEBUG
  1342. int FEpanic;
  1343. X
  1344. sig_t FEChld(SIGDEFARG)
  1345. X{
  1346. X  FEpanic=1;
  1347. X#ifndef SIGVOID
  1348. X  return((sig_t) 0);
  1349. X#endif
  1350. X}
  1351. X#endif
  1352. X
  1353. static sig_t SigChld(SIGDEFARG)
  1354. X{
  1355. X  debug("SigChld()\n");
  1356. X  GotSignal = 1;
  1357. X#ifndef SIGVOID
  1358. X  return((sig_t) 0);
  1359. X#endif
  1360. X}
  1361. X
  1362. sig_t SigHup(SIGDEFARG)
  1363. X{
  1364. X  debug("SigHup()\n");
  1365. X  if (auto_detach)
  1366. X    Detach(D_DETACH);
  1367. X  else
  1368. X    Finit(0);
  1369. X#ifndef SIGVOID
  1370. X  return((sig_t) 0);
  1371. X#endif
  1372. X}
  1373. X
  1374. static sig_t SigInt(SIGDEFARG)
  1375. X{
  1376. X  char buf[1];
  1377. X
  1378. X  debug("SigInt()\n");
  1379. X  *buf = (char) intrc;
  1380. X  inlen[ForeNum] = 0;
  1381. X  if (fore && !in_ovl)
  1382. X    write(fore->ptyfd, buf, 1);
  1383. X  signal(SIGINT, SigInt);
  1384. X#ifndef SIGVOID
  1385. X  return((sig_t) 0);
  1386. X#endif
  1387. X}
  1388. X
  1389. static sig_t CoreDump(sig)
  1390. int sig;
  1391. X{
  1392. X  setgid(getgid());
  1393. X  setuid(getuid());
  1394. X  unlink("core");
  1395. X  fprintf(stderr, "\r\n[screen caught signal %d. (core dumped)]\r\n", sig);
  1396. X  fflush(stderr);
  1397. X  Kill(AttacherPid, SIG_BYE);
  1398. X  abort();
  1399. X#ifndef SIGVOID
  1400. X  return((sig_t) 0);
  1401. X#endif
  1402. X}
  1403. X
  1404. static void DoWait()
  1405. X{
  1406. X  register int n, next, pid;
  1407. X#ifdef BSDWAIT
  1408. X  union wait wstat;
  1409. X#else
  1410. X  int wstat;
  1411. X#endif
  1412. X
  1413. X#ifdef BSDJOBS
  1414. X# ifndef BSDWAIT
  1415. X  while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
  1416. X# else
  1417. X  while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
  1418. X# endif
  1419. X#else    /* BSDJOBS */
  1420. X  while ((pid = wait(&wstat)) < 0)
  1421. X    if (errno != EINTR)
  1422. X      break;
  1423. X  if (pid >= 0)
  1424. X#endif    /* BSDJOBS */
  1425. X    {
  1426. X      for (n = WinList; n != -1; n = next)
  1427. X    {
  1428. X      next = wtab[n]->WinLink;
  1429. X      if (pid == wtab[n]->wpid)
  1430. X        {
  1431. X#ifdef BSDJOBS
  1432. X          if (WIFSTOPPED(wstat))
  1433. X        {
  1434. X          Msg(0, "Child has been stopped, restarting.");
  1435. X          debug1("WIFSTOPPED: %d SIGCONT\n", wtab[n]->wpid);
  1436. X          if (killpg(wtab[n]->wpid, SIGCONT))
  1437. X            kill(wtab[n]->wpid, SIGCONT);
  1438. X        }
  1439. X          else
  1440. X#endif
  1441. X        KillWindow(n);
  1442. X        }
  1443. X    }
  1444. X    }
  1445. X}
  1446. X
  1447. void KillWindow(n)
  1448. int n;
  1449. X{
  1450. X  register int i;
  1451. X  /*
  1452. X   * Remove window from linked list.
  1453. X   */
  1454. X  if (n == WinList)    /* WinList = ForeNum */
  1455. X    {
  1456. X      RemoveStatus();
  1457. X      WinList = fore->WinLink;
  1458. X      fore = 0;
  1459. X    }
  1460. X  else
  1461. X    {
  1462. X      i = WinList;
  1463. X      while (wtab[i]->WinLink != n)
  1464. X    i = wtab[i]->WinLink;
  1465. X      wtab[i]->WinLink = wtab[n]->WinLink;
  1466. X    }
  1467. X  FreeWindow(wtab[n]);
  1468. X  wtab[n] = 0;
  1469. X  if (inlen[n] > 0)
  1470. X    {
  1471. X      inlen[n] = 0;
  1472. X      inbuf_ct--;
  1473. X    }
  1474. X  /*
  1475. X   * If the foreground window disappeared check the head of the linked list
  1476. X   * of windows for the most recently used window. If no window is alive at
  1477. X   * all, exit.
  1478. X   */
  1479. X  if (WinList == -1)
  1480. X    Finit(0);
  1481. X  if (!fore)
  1482. X    SwitchWindow(WinList);
  1483. X}
  1484. X
  1485. static sig_t Finit(i)
  1486. int i;
  1487. X{
  1488. X  register int n, next;
  1489. X
  1490. X#ifdef SYSV
  1491. X  signal(SIGCLD, SIG_IGN);
  1492. X#else
  1493. X  signal(SIGCHLD, SIG_IGN);
  1494. X#endif
  1495. X  signal(SIGHUP, SIG_IGN);
  1496. X  debug1("Finit(%d);\n", i);
  1497. X  for (n = WinList; n != -1; n = next)
  1498. X    {
  1499. X      next = wtab[n]->WinLink;
  1500. X      FreeWindow(wtab[n]);
  1501. X    }
  1502. X  FinitTerm();
  1503. X  SetTTY(0, &OldMode);
  1504. X#ifdef UTMPOK
  1505. X  RestoreLoginSlot();
  1506. X#endif
  1507. X  printf("\n[screen is terminating]\n");
  1508. X  freetty();
  1509. X  if (ServerSocket != -1)
  1510. X    {
  1511. X      debug1("we unlink(%s)\n", SockPath);
  1512. X      (void) unlink(SockPath);
  1513. X    }
  1514. X  Kill(AttacherPid, SIG_BYE);
  1515. X  exit(i);
  1516. X#ifndef SIGVOID
  1517. X  return((sig_t) 0);
  1518. X#endif
  1519. X}
  1520. X
  1521. void
  1522. eexit(e)
  1523. int e;
  1524. X{
  1525. X  if (ServerSocket != -1)
  1526. X    {
  1527. X      debug1("we unlink(%s)\n", SockPath);
  1528. X      (void) unlink(SockPath);
  1529. X    }
  1530. X  exit(e);
  1531. X}
  1532. X
  1533. static void InitKeytab()
  1534. X{
  1535. X  register int i;
  1536. X
  1537. X  for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
  1538. X    ktab[i].type = KEY_IGNORE;
  1539. X
  1540. X  ktab['h'].type = ktab[Ctrl('h')].type = KEY_HARDCOPY;
  1541. X#ifdef BSDJOBS
  1542. X  ktab['z'].type = ktab[Ctrl('z')].type = KEY_SUSPEND;
  1543. X#endif
  1544. X  ktab['c'].type = ktab[Ctrl('c')].type = KEY_SHELL;
  1545. X  ktab[' '].type = ktab[Ctrl(' ')].type =
  1546. X    ktab['n'].type = ktab[Ctrl('n')].type = KEY_NEXT;
  1547. X  ktab['-'].type = ktab['p'].type = ktab[Ctrl('p')].type = KEY_PREV;
  1548. X  ktab['k'].type = ktab[Ctrl('k')].type = KEY_KILL;
  1549. X  ktab['l'].type = ktab[Ctrl('l')].type = KEY_REDISPLAY;
  1550. X  ktab['w'].type = ktab[Ctrl('w')].type = KEY_WINDOWS;
  1551. X  ktab['v'].type = ktab[Ctrl('v')].type = KEY_VERSION;
  1552. X  ktab['q'].type = ktab[Ctrl('q')].type = KEY_XON;
  1553. X  ktab['s'].type = ktab[Ctrl('s')].type = KEY_XOFF;
  1554. X  ktab['t'].type = ktab[Ctrl('t')].type = KEY_TIME;
  1555. X  ktab['i'].type = ktab[Ctrl('i')].type = KEY_INFO;
  1556. X  ktab['m'].type = ktab[Ctrl('m')].type = KEY_LASTMSG;
  1557. X  ktab['A'].type = KEY_AKA, ktab['A'].args = NULL;
  1558. X  ktab['L'].type = KEY_LOGIN;
  1559. X  ktab[','].type = KEY_LICENSE;
  1560. X  ktab['W'].type = KEY_WIDTH;
  1561. X  ktab['.'].type = KEY_TERMCAP;
  1562. X  ktab[Ctrl('\\')].type = KEY_QUIT;
  1563. X  ktab['d'].type = ktab[Ctrl('d')].type = KEY_DETACH;
  1564. X  ktab['r'].type = ktab[Ctrl('r')].type = KEY_WRAP;
  1565. X  ktab['f'].type = ktab[Ctrl('f')].type = KEY_FLOW;
  1566. X  ktab['/'].type = KEY_AUTOFLOW;
  1567. X  ktab['C'].type = KEY_CLEAR;
  1568. X  ktab['Z'].type = KEY_RESET;
  1569. X  ktab['H'].type = KEY_LOGTOGGLE;
  1570. X  if (Esc != MetaEsc)
  1571. X    ktab[Esc].type = KEY_OTHER;
  1572. X  else
  1573. X    ktab[Esc].type = KEY_IGNORE;
  1574. X  ktab['M'].type = KEY_MONITOR;
  1575. X  ktab['?'].type = KEY_HELP;
  1576. X  for (i = 0; i <= 9; i++)
  1577. X    ktab['0' + i].type = (enum keytype) (i + (int)KEY_0);
  1578. X  ktab[Ctrl('G')].type = KEY_VBELL;
  1579. X  ktab[':'].type = KEY_COLON;
  1580. X#ifdef COPY_PASTE
  1581. X  ktab['['].type = ktab[Ctrl('[')].type = KEY_COPY;
  1582. X  ktab[']'].type = ktab[Ctrl(']')].type = KEY_PASTE;
  1583. X  ktab['{'].type = KEY_HISTORY; /* } */
  1584. X  ktab['>'].type = KEY_WRITE_BUFFER;
  1585. X  ktab['<'].type = KEY_READ_BUFFER;
  1586. X  ktab['='].type = KEY_REMOVE_BUFFERS;
  1587. X#endif
  1588. X#ifdef POW_DETACH
  1589. X  ktab['D'].type = KEY_POW_DETACH;
  1590. X#endif
  1591. X#ifdef LOCK
  1592. X  ktab['x'].type = ktab[Ctrl('x')].type = KEY_LOCK;
  1593. X#endif
  1594. X}
  1595. X
  1596. X/*
  1597. X * this is a braindamaged hack: if (obuf == NULL) then we provided
  1598. X * a key_type as a second char in ibuf. not a key.
  1599. X */
  1600. char *ProcessInput(ibuf, pilen, obuf, polen, obuf_size)
  1601. char *ibuf, *obuf;
  1602. register int *pilen, *polen, obuf_size;
  1603. X{
  1604. X  register int n;
  1605. X  register enum keytype k;
  1606. X  register char *s, *p;
  1607. X  char buf[2];
  1608. X  int newwidth;
  1609. X
  1610. X  if (!obuf)
  1611. X    obuf_size = 0;
  1612. X
  1613. X  for (s = ibuf, p = obuf + *polen; *pilen > 0; --*pilen, s++)
  1614. X    {
  1615. X      if (*s == Esc)
  1616. X    {
  1617. X      debug2("'%c %c ", s[0], s[1]);
  1618. X      debug2("%c %c' ", s[2], s[3]);
  1619. X      if (*pilen > 1)
  1620. X        {
  1621. X          --*pilen;
  1622. X          s++;
  1623. X#if defined(GOULD_NP1)
  1624. X          k = (obuf)?(ktab[*s].type):(enum keytype)(int)(*s);
  1625. X#else
  1626. X          k = (obuf)?(ktab[*s].type):(enum keytype)(*s);
  1627. X#endif
  1628. X          debug2("Processinput C-A %02x '%c' ", k, k);
  1629. X          debug1("%s\n", (obuf)?"std":"NOOBUF");
  1630. X          if (*s == MetaEsc)
  1631. X        {
  1632. X          if (*polen < obuf_size)
  1633. X            {
  1634. X              *p++ = Esc;
  1635. X              ++*polen;
  1636. X            }
  1637. X        }
  1638. X          else if ((int)k >= (int)KEY_0 && (int)k <= (int)KEY_9)
  1639. X        SwitchWindow((int)k - (int)KEY_0);
  1640. X          else
  1641. X        switch (k)
  1642. X          {
  1643. X          case KEY_TERMCAP:
  1644. X            WriteFile(DUMP_TERMCAP);
  1645. X            break;
  1646. X          case KEY_HARDCOPY:
  1647. X            WriteFile(DUMP_HARDCOPY);
  1648. X            break;
  1649. X          case KEY_LOGTOGGLE:
  1650. X            LogToggle();
  1651. X            break;
  1652. X#ifdef BSDJOBS
  1653. X          case KEY_SUSPEND:
  1654. X            *pilen = 0;
  1655. X            Detach(D_STOP);
  1656. X            break;
  1657. X#endif
  1658. X          case KEY_SHELL:
  1659. X            debug("calling MakeWindow with shell\n");
  1660. X            MakeWindow(shellaka, ShellArgs,
  1661. X                   0, flowctl, 0, (char *) 0, loginflag, -1, 0);
  1662. X            break;
  1663. X          case KEY_NEXT:
  1664. X            if (MoreWindows())
  1665. X              SwitchWindow(NextWindow());
  1666. X            break;
  1667. X          case KEY_PREV:
  1668. X            if (MoreWindows())
  1669. X              SwitchWindow(PreviousWindow());
  1670. X            break;
  1671. X          case KEY_KILL:
  1672. X            KillWindow(n = ForeNum);
  1673. X#ifdef NETHACK
  1674. X                  if (nethackflag)
  1675. X              Msg(0, "You destroy poor window %d", n);
  1676. X#endif
  1677. X            break;
  1678. X          case KEY_QUIT:
  1679. X            Finit(0);
  1680. X            /* NOTREACHED */
  1681. X          case KEY_DETACH:
  1682. X            *pilen = 0;
  1683. X            Detach(D_DETACH);
  1684. X            break;
  1685. X#ifdef POW_DETACH
  1686. X          case KEY_POW_DETACH:
  1687. X            *pilen = 0;
  1688. X            buf[0] = *s;
  1689. X            buf[1] = '\0';
  1690. X            Msg(0, buf);
  1691. X            read(0, buf, 1);
  1692. X            if (*buf == *s)
  1693. X              Detach(D_POWER); /* detach and kill Attacher's
  1694. X                    * parent     */
  1695. X            else
  1696. X              {
  1697. X            write(1, "\007", 1);
  1698. X            RemoveStatus();
  1699. X#ifdef NETHACK
  1700. X                  if (nethackflag)
  1701. X               Msg(0, "The blast of disintegration whizzes by you!");
  1702. X#endif
  1703. X              }
  1704. X            break;
  1705. X#endif
  1706. X          case KEY_REDISPLAY:
  1707. X            Activate();
  1708. X            break;
  1709. X          case KEY_WINDOWS:
  1710. X            ShowWindows();
  1711. X            break;
  1712. X          case KEY_VERSION:
  1713. X            Msg(0, "screen %d.%.2d.%.2d%s (%s) %s",REV, VERS, PATCHLEVEL, STATE, ORIGIN, DATE);
  1714. X            break;
  1715. X          case KEY_TIME:
  1716. X            ShowTime();
  1717. X            break;
  1718. X          case KEY_INFO:
  1719. X            ShowInfo();
  1720. X            break;
  1721. X          case KEY_OTHER:
  1722. X            if (MoreWindows())
  1723. X              SwitchWindow(fore->WinLink);
  1724. X            break;
  1725. X          case KEY_XON:
  1726. X            if (*polen < obuf_size)
  1727. X              {
  1728. X            *p++ = Ctrl('q');
  1729. X            ++*polen;
  1730. X              }
  1731. X            break;
  1732. X          case KEY_XOFF:
  1733. X            if (*polen < obuf_size)
  1734. X              {
  1735. X            *p++ = Ctrl('s');
  1736. X            ++*polen;
  1737. X              }
  1738. X            break;
  1739. X#ifdef LOCK
  1740. X          case KEY_LOCK:
  1741. X            Detach(D_LOCK); /* do it micha's way */
  1742. X            break;
  1743. X#endif
  1744. X          case KEY_WIDTH:
  1745. X            if (Z0 || WS)
  1746. X              {
  1747. X            if (fore->width == Z0width)
  1748. X              newwidth=Z1width;
  1749. X            else if (fore->width == Z1width)
  1750. X              newwidth=Z0width;
  1751. X            else if (fore->width > (Z0width+Z1width)/2)
  1752. X              newwidth=Z0width;
  1753. X            else
  1754. X              newwidth=Z1width;
  1755. X            ChangeWindowSize(fore, newwidth, fore->height);
  1756. X            Activate();
  1757. X              }
  1758. X            else
  1759. X              Msg(0, "Your termcap does not specify how to change the terminal's width.");
  1760. X            break;
  1761. X          case KEY_LOGIN:
  1762. X            SlotToggle(0);
  1763. X            break;
  1764. X          case KEY_AKA:
  1765. X            if (!ktab[*s].args)
  1766. X              InputAKA();
  1767. X            else
  1768. X              strncpy(fore->cmd + fore->akapos, ktab[*s].args[0], 20);
  1769. X            break;
  1770. X          case KEY_COLON:
  1771. X            InputColon();
  1772. X            break;
  1773. X          case KEY_LASTMSG:
  1774. X            Msg(0, "%s", LastMsg);
  1775. X            break;
  1776. X          case KEY_SET:
  1777. X            DoSet(ktab[*s].args);
  1778. X            break;
  1779. X          case KEY_SCREEN:
  1780. X            debug3("KEY_SCREEN DoSc(, ktab[%d].args(='%s','%s')...)\n",
  1781. X               *s, ktab[*s].args[0], ktab[*s].args[1]);
  1782. X            DoScreen("key", ktab[*s].args);
  1783. X            break;
  1784. X          case KEY_CREATE:
  1785. X            debug2("KEY_CREATE MaWi(0, ktab[%d].args(='%s')...)\n",
  1786. X               *s, ktab[*s].args);
  1787. X            MakeWindow((char *) 0, ktab[*s].args,
  1788. X                0, flowctl, 0, (char *) 0, loginflag, -1, 0);
  1789. X            break;
  1790. X          case KEY_WRAP:
  1791. X            fore->wrap = !fore->wrap;
  1792. X            Msg(0, "%cwrap", fore->wrap ? '+' : '-');
  1793. X            break;
  1794. X          case KEY_FLOW:
  1795. X            ToggleFlow();
  1796. X            goto flow_msg;
  1797. X          case KEY_AUTOFLOW:
  1798. X            if ((fore->autoflow = !fore->autoflow) != 0
  1799. X            && fore->flow == fore->keypad)
  1800. X              ToggleFlow();
  1801. X          flow_msg:
  1802. X            Msg(0, "%cflow%s", fore->flow ? '+' : '-',
  1803. X            fore->autoflow ? "(auto)" : "");
  1804. X            break;
  1805. X          case KEY_CLEAR:
  1806. X            if (fore->state == LIT)
  1807. X              WriteString(fore, "\033[H\033[J", 6);
  1808. X            break;
  1809. X          case KEY_RESET:
  1810. X            if (fore->state == LIT)
  1811. X              WriteString(fore, "\033c", 2);
  1812. X            break;
  1813. X          case KEY_MONITOR:
  1814. X            if (fore->monitor == MON_OFF)
  1815. X              {
  1816. X            fore->monitor = MON_ON;
  1817. X            Msg(0,
  1818. X                "Window %d is now being monitored for all activity.",
  1819. X                ForeNum);
  1820. X              }
  1821. X            else
  1822. X              {
  1823. X            fore->monitor = MON_OFF;
  1824. X            Msg(0,
  1825. X                "Window %d is no longer being monitored for activity.",
  1826. X                ForeNum);
  1827. X              }
  1828. X            break;
  1829. X          case KEY_HELP:
  1830. X            display_help();
  1831. X            break;
  1832. X          case KEY_LICENSE:
  1833. X            display_copyright();
  1834. X            break;
  1835. X#ifdef COPY_PASTE
  1836. X          case KEY_COPY:
  1837. X            /* SetOvlCurr(); */
  1838. X            (void) MarkRoutine(PLAIN);
  1839. X            break;
  1840. X          case KEY_HISTORY:
  1841. X            /* SetOvlCurr(); */
  1842. X            if (MarkRoutine(TRICKY))
  1843. X              if (copybuffer != NULL)
  1844. X            {
  1845. X              pastelen = copylen;
  1846. X              pastebuffer = copybuffer;
  1847. X              debug1("history new copylen: %d\n", pastelen);
  1848. X            }
  1849. X            break;
  1850. X          case KEY_PASTE:
  1851. X            if (copybuffer == NULL)
  1852. X              {
  1853. X#ifdef NETHACK
  1854. X                  if (nethackflag)
  1855. X              Msg(0, "Nothing happens.");
  1856. X                  else
  1857. X#endif
  1858. X            Msg(0, "empty buffer");
  1859. X            copylen = 0;
  1860. X            break;
  1861. X              }
  1862. X            pastelen = copylen;
  1863. X            pastebuffer = copybuffer;
  1864. X            break;
  1865. X          case KEY_WRITE_BUFFER:
  1866. X            if (copybuffer == NULL)
  1867. X              {
  1868. X#ifdef NETHACK
  1869. X                  if (nethackflag)
  1870. X              Msg(0, "Nothing happens.");
  1871. X                  else
  1872. X#endif
  1873. X            Msg(0, "empty buffer");
  1874. X            copylen = 0;
  1875. X            break;
  1876. X              }
  1877. X            WriteFile(DUMP_EXCHANGE);
  1878. X            break;
  1879. X          case KEY_READ_BUFFER:
  1880. X            ReadFile();
  1881. X            break;
  1882. X          case KEY_REMOVE_BUFFERS:
  1883. X            KillBuffers();
  1884. X            break;
  1885. X#endif                /* COPY_PASTE */
  1886. X          case KEY_VBELL:
  1887. X            if (visual_bell)
  1888. X              {
  1889. X            visual_bell = 0;
  1890. X            Msg(0, ":vbell off");
  1891. X              }
  1892. X            else
  1893. X              {
  1894. X            visual_bell = 1;
  1895. X            Msg(0, ":vbell on");
  1896. X              }
  1897. X            break;
  1898. X           default:
  1899. X            break;
  1900. X          }
  1901. X        }
  1902. X      else
  1903. X        ESCseen = 1;
  1904. X      --*pilen;
  1905. X      s++;
  1906. X      break;
  1907. X    }
  1908. X      else if (*polen < obuf_size)
  1909. X    {
  1910. X      *p++ = *s;
  1911. X      ++*polen;
  1912. X    }
  1913. X    }
  1914. X  return (s);
  1915. X}
  1916. X
  1917. X/* Send a terminal report as if it were typed. */ 
  1918. void
  1919. Report(wp, fmt, n1, n2)
  1920. struct win *wp;
  1921. char *fmt;
  1922. int n1, n2;
  1923. X{
  1924. X  register int n, len;
  1925. X  char rbuf[40];
  1926. X
  1927. X  sprintf(rbuf, fmt, n1, n2);
  1928. X  len = strlen(rbuf);
  1929. X
  1930. X  for (n = 0; n < MAXWIN; n++)
  1931. X    {
  1932. X      if (wp == wtab[n])
  1933. X    {
  1934. X      if (inlen[n] + len <= sizeof *inbuf)
  1935. X        {
  1936. X          bcopy(rbuf, inbuf[n] + inlen[n], len);
  1937. X          if (inlen[n] == 0)
  1938. X        inbuf_ct++;
  1939. X          inlen[n] += len;
  1940. X        }
  1941. X      break;
  1942. X    }
  1943. X    }/* for */
  1944. X}
  1945. X
  1946. void
  1947. SwitchWindow(n)
  1948. int n;
  1949. X{
  1950. X  debug1("SwitchWindow %d\n", n);
  1951. X  if (!wtab[n])
  1952. X    {
  1953. X      ShowWindows();
  1954. X      return;
  1955. X    }
  1956. X  if (wtab[n] == fore)
  1957. X    {
  1958. X      Msg(0, "This IS window %d.", n);
  1959. X      return;
  1960. X    }
  1961. X  SetForeWindow(n);
  1962. X  if (!Detached && !in_ovl)
  1963. X    Activate();
  1964. X}
  1965. X
  1966. static void SetForeWindow(n)
  1967. int n;
  1968. X{
  1969. X  /*
  1970. X   * If we come from another window, make it inactive.
  1971. X   */
  1972. X  if (fore)
  1973. X    fore->active = 0;
  1974. X  ForeNum = n;
  1975. X  fore = wtab[n];
  1976. X  if (!Detached && !in_ovl)
  1977. X    fore->active = 1;
  1978. X  /*
  1979. X   * Place the window at the head of the most-recently-used list.
  1980. X   */
  1981. X  if ((n = WinList) != ForeNum)
  1982. X    {
  1983. X      /*
  1984. X       * we had a bug here. we sometimes ran into n = -1; and crashed.
  1985. X       * (this is not the perfect fix. "if(...) break;" inserted. jw.)
  1986. X       */
  1987. X      while (wtab[n]->WinLink != ForeNum)
  1988. X    {
  1989. X      if (wtab[n]->WinLink == -1)
  1990. X        break;
  1991. X      n = wtab[n]->WinLink;
  1992. X    }
  1993. X      wtab[n]->WinLink = fore->WinLink;
  1994. X      fore->WinLink = WinList;
  1995. X      WinList = ForeNum;
  1996. X    }
  1997. X}
  1998. X
  1999. static int NextWindow()
  2000. X{
  2001. X  register struct win **pp;
  2002. X
  2003. X  for (pp = wtab + ForeNum + 1; pp != wtab + ForeNum; ++pp)
  2004. X    {
  2005. X      if (pp == wtab + MAXWIN)
  2006. X    pp = wtab;
  2007. X      if (*pp)
  2008. X    break;
  2009. X    }
  2010. X  return pp - wtab;
  2011. X}
  2012. X
  2013. static int PreviousWindow()
  2014. X{
  2015. X  register struct win **pp;
  2016. X
  2017. X  for (pp = wtab + ForeNum - 1; pp != wtab + ForeNum; --pp)
  2018. X    {
  2019. X      if (pp < wtab)
  2020. X    pp = wtab + MAXWIN - 1;
  2021. X      if (*pp)
  2022. X    break;
  2023. X    }
  2024. X  return pp - wtab;
  2025. X}
  2026. X
  2027. static int MoreWindows()
  2028. X{
  2029. X  if (fore->WinLink != -1)
  2030. X    return 1;
  2031. X  Msg(0, "No other window.");
  2032. X  return 0;
  2033. X}
  2034. X
  2035. static void FreeWindow(wp)
  2036. struct win *wp;
  2037. X{
  2038. X#ifdef UTMPOK
  2039. X  RemoveUtmp(wp);
  2040. X#endif
  2041. X#ifdef SUIDROOT
  2042. X  (void) chmod(wp->tty, 0666);
  2043. X  (void) chown(wp->tty, 0, 0);
  2044. X#endif
  2045. X  close(wp->ptyfd);
  2046. X  if (wp->logfp != NULL)
  2047. X    fclose(wp->logfp);
  2048. X  ChangeWindowSize(wp, 0, 0);
  2049. X  Free(wp);
  2050. X}
  2051. X
  2052. int
  2053. MakeWindow(prog, args, aflag, flowflag, StartAt, dir, lflag, histheight, term)
  2054. char *prog, **args, *dir;
  2055. int aflag, flowflag, StartAt, lflag, histheight;
  2056. char *term; /* if term is nonzero we assume it "vt100" or the like.. */
  2057. X{
  2058. X  register struct win **pp, *p;
  2059. X  register int n, f;
  2060. X  int tf, tlflag;
  2061. X  char ebuf[10];
  2062. X#ifndef TIOCSWINSZ
  2063. X  char libuf[20], cobuf[20];
  2064. X#endif
  2065. X  char tebuf[25];
  2066. X
  2067. X  pp = wtab + StartAt;
  2068. X  do
  2069. X    {
  2070. X      if (*pp == 0)
  2071. X    break;
  2072. X      if (++pp == wtab + MAXWIN)
  2073. X    pp = wtab;
  2074. X    } while (pp != wtab + StartAt);
  2075. X  if (*pp)
  2076. X    {
  2077. X      Msg(0, "No more windows.");
  2078. X      return -1;
  2079. X    }
  2080. X
  2081. X   if (((tlflag = lflag) == -1) && ((tlflag = loginflag) == -1))
  2082. X    tlflag = LOGINDEFAULT;
  2083. X
  2084. X#ifdef USRLIMIT
  2085. X  /*
  2086. X   * Count current number of users, if logging windows in.
  2087. X   */
  2088. X  if (tlflag == 1 && CountUsers() >= USRLIMIT)
  2089. X    {
  2090. X      Msg(0, "User limit reached.  Window will not be logged in.");
  2091. X      tlflag = 0;
  2092. X    }
  2093. X#endif
  2094. X  n = pp - wtab;
  2095. X  debug1("Makewin creating %d\n", n);
  2096. X  if ((f = OpenPTY()) == -1)
  2097. X    {
  2098. X      Msg(0, "No more PTYs.");
  2099. X      return -1;
  2100. X    }
  2101. X#ifdef SYSV
  2102. X  (void) fcntl(f, F_SETFL, O_NDELAY);
  2103. X#else
  2104. X  (void) fcntl(f, F_SETFL, FNDELAY);
  2105. X#endif
  2106. X  if ((p = (struct win *) malloc(sizeof(struct win))) == 0)
  2107. X    {
  2108. X      close(f);
  2109. X      Msg_nomem;
  2110. X      return -1;
  2111. X    }
  2112. X  bzero((char *) p, (int) sizeof(struct win));
  2113. X  p->ptyfd = f;
  2114. X  p->aflag = aflag;
  2115. X  if (!flowflag)
  2116. X    flowflag = flowctl;
  2117. X  p->flow = (flowflag != 1);
  2118. X  p->autoflow = (flowflag == 3);
  2119. X  if (!prog)
  2120. X    prog = Filename(args[0]);
  2121. X  strncpy(p->cmd, prog, MAXSTR - 1);
  2122. X  if ((prog = rindex(p->cmd, '|')) != NULL)
  2123. X    {
  2124. X      *prog++ = '\0';
  2125. X      prog += strlen(prog);
  2126. X      p->akapos = prog - p->cmd;
  2127. X      p->autoaka = 0;
  2128. X    }
  2129. X  else
  2130. X    p->akapos = 0;
  2131. X  p->monitor = default_monitor;
  2132. X  strncpy(p->tty, TtyName, MAXSTR - 1);
  2133. X#ifdef SUIDROOT
  2134. X  (void) chown(TtyName, real_uid, real_gid);
  2135. X# ifdef UTMPOK
  2136. X  (void) chmod(TtyName, tlflag ? TtyMode : (TtyMode & ~022));
  2137. X# else
  2138. X  (void) chmod(TtyName, TtyMode);
  2139. X# endif
  2140. X#endif
  2141. X
  2142. X  if (histheight < 0)
  2143. X    histheight = default_histheight;
  2144. X  if (ChangeWindowSize(p, default_width, default_height))
  2145. X    {
  2146. X      FreeWindow(p);
  2147. X      return -1;
  2148. X    }
  2149. X  ChangeScrollback(p, histheight, default_width);
  2150. X  ResetScreen(p);
  2151. X  debug("forking...\n");
  2152. X  switch (p->wpid = fork())
  2153. X    {
  2154. X    case -1:
  2155. X      Msg(errno, "fork");
  2156. X      FreeWindow(p);
  2157. X      return -1;
  2158. X    case 0:
  2159. X      signal(SIGHUP, SIG_DFL);
  2160. X      signal(SIGINT, SIG_DFL);
  2161. X      signal(SIGQUIT, SIG_DFL);
  2162. X      signal(SIGTERM, SIG_DFL);
  2163. X#ifdef BSDJOBS
  2164. X      signal(SIGTTIN, SIG_DFL);
  2165. X      signal(SIGTTOU, SIG_DFL);
  2166. X#else
  2167. X      setpgrp();
  2168. X#endif
  2169. X      setuid(real_uid);
  2170. X      setgid(real_gid);
  2171. X      if (dir && chdir(dir) == -1)
  2172. X    {
  2173. X      SendErrorMsg("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  2174. X      eexit(1);
  2175. X    }
  2176. X
  2177. X      freetty();
  2178. X#ifdef SYSV
  2179. X      setpgrp();
  2180. X#endif
  2181. X      if ((tf = open(TtyName, O_RDWR)) == -1)
  2182. X    {
  2183. X      SendErrorMsg("Cannot open %s: %s", TtyName, sys_errlist[errno]);
  2184. X      eexit(1);
  2185. X    }
  2186. X#ifdef SVR4
  2187. X      if (ioctl(tf, I_PUSH, "ptem"))
  2188. X    {
  2189. X      SendErrorMsg("Cannot I_PUSH ptem %s %s", TtyName, sys_errlist[errno]);
  2190. X      eexit(1);
  2191. X    }
  2192. X      if (ioctl(tf, I_PUSH, "ldterm"))
  2193. X    {
  2194. X      SendErrorMsg("Cannot I_PUSH ldterm %s %s", TtyName, sys_errlist[errno]);
  2195. X      eexit(1);
  2196. X    }
  2197. X      if (ioctl(tf, I_PUSH, "ttcompat"))
  2198. X    {
  2199. X      SendErrorMsg("Cannot I_PUSH ttcompat %s %s", TtyName, sys_errlist[errno]);
  2200. X      eexit(1);
  2201. X    }
  2202. X#endif
  2203. X      (void) dup2(tf, 0);
  2204. X      (void) dup2(tf, 1);
  2205. X      (void) dup2(tf, 2);
  2206. X#ifdef DEBUG
  2207. X      dfp = stderr;
  2208. X#endif
  2209. X#ifdef SYSV
  2210. X      for (f = NOFILE - 1; f > 2; f--)
  2211. X    close(f);
  2212. X#else
  2213. X      for (f = getdtablesize() - 1; f > 2; f--)
  2214. X    close(f);
  2215. X#endif
  2216. X      fgtty();
  2217. X#ifdef TIOCSWINSZ
  2218. X      glwz.ws_col=p->width;
  2219. X      glwz.ws_row=p->height;
  2220. X      (void) ioctl(0, TIOCSWINSZ, &glwz);
  2221. X#else
  2222. X      sprintf(libuf, "LINES=%d", p->height);
  2223. X      sprintf(cobuf, "COLUMNS=%d", p->width);
  2224. X      NewEnv[4] = libuf;
  2225. X      NewEnv[5] = cobuf;
  2226. X#endif
  2227. X      SetTTY(0, &OldMode);
  2228. X      if (aflag)
  2229. X        NewEnv[2] = MakeTermcap(1);
  2230. X      else
  2231. X        NewEnv[2] = Termcap;
  2232. X      if (term && *term && strcmp(screenterm, term) &&
  2233. X      ((unsigned)strlen(term) < 20))
  2234. X    {
  2235. X          char *s1, *s2, tl;
  2236. X
  2237. X      sprintf(tebuf, "TERM=%s", term);
  2238. X      debug2("Makewindow %d with %s\n", n, tebuf);
  2239. X          tl = strlen(term);
  2240. X      NewEnv[1] = tebuf;
  2241. X          if (s1 = index(Termcap, '|'))
  2242. X        {
  2243. X          if (s2 = index(++s1, '|'))
  2244. X        {
  2245. X          if (strlen(Termcap) - (s2 - s1) + tl < 1024)
  2246. X            {
  2247. X              bcopy(s2, s1 + tl, strlen(s2) + 1);
  2248. X              bcopy(term, s1, tl);
  2249. X            }
  2250. X        }
  2251. X            }
  2252. X    }
  2253. X      sprintf(ebuf, "WINDOW=%d", n);
  2254. X      NewEnv[3] = ebuf;
  2255. X
  2256. X      execvpe(*args, args, NewEnv);
  2257. X      SendErrorMsg("Cannot exec %s: %s", *args, sys_errlist[errno]);
  2258. X      exit(1);
  2259. X    } /* end fork switch */
  2260. X  /*
  2261. X   * Place the newly created window at the head of the most-recently-used list.
  2262. X   */
  2263. X  *pp = p;
  2264. X  p->WinLink = WinList;
  2265. X  WinList = n;
  2266. X  HasWindow = 1;
  2267. X#ifdef UTMPOK
  2268. X  debug1("MakeWindow will %slog in.\n", tlflag?"":"not ");
  2269. X  if (tlflag == 1)
  2270. X    SetUtmp(p, n);
  2271. X  else
  2272. X    p->slot = (slot_t) -1;
  2273. X#endif
  2274. X  SetForeWindow(n);
  2275. X  Activate();
  2276. X  return n;
  2277. X}
  2278. X
  2279. static void execvpe(prog, args, env)
  2280. char *prog, **args, **env;
  2281. X{
  2282. X  register char *path, *p;
  2283. X  char buf[1024];
  2284. X  char *shargs[MAXARGS + 1];
  2285. X  register int i, eaccess = 0;
  2286. X
  2287. X  if (prog[0] == '/')
  2288. X    path = "";
  2289. X  else if ((path = getenv("PATH")) == 0)
  2290. X    path = DefaultPath;
  2291. X  do
  2292. X    {
  2293. X      p = buf;
  2294. X      while (*path && *path != ':')
  2295. X    *p++ = *path++;
  2296. X      if (p > buf)
  2297. X    *p++ = '/';
  2298. X      strcpy(p, prog);
  2299. X      if (*path)
  2300. X    ++path;
  2301. X      execve(buf, args, env);
  2302. X      switch (errno)
  2303. X    {
  2304. X    case ENOEXEC:
  2305. X      shargs[0] = DefaultShell;
  2306. X      shargs[1] = buf;
  2307. X      for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
  2308. X        ;
  2309. X      execve(DefaultShell, shargs, env);
  2310. X      return;
  2311. X    case EACCES:
  2312. X      eaccess = 1;
  2313. X      break;
  2314. X    case ENOMEM:
  2315. X    case E2BIG:
  2316. X    case ETXTBSY:
  2317. X      return;
  2318. X    }
  2319. X    } while (*path);
  2320. X  if (eaccess)
  2321. X    errno = EACCES;
  2322. X}
  2323. X
  2324. X
  2325. static void LogToggle()
  2326. X{
  2327. X  char buf[1024];
  2328. X
  2329. X  sprintf(buf, "screenlog.%d", ForeNum);
  2330. X  if (fore->logfp != NULL)
  2331. X    {
  2332. X      Msg(0, "Logfile \"%s\" closed.", buf);
  2333. X      fclose(fore->logfp);
  2334. X      fore->logfp = NULL;
  2335. X      return;
  2336. X    }
  2337. X  if ((fore->logfp = secfopen(buf, "a")) == NULL)
  2338. X    {
  2339. X      Msg(errno, "Error opening logfile \"%s\"", buf);
  2340. X      return;
  2341. X    }
  2342. X  Msg(0, "%s logfile \"%s\"", ftell(fore->logfp) ? "Appending to" : "Creating", buf);
  2343. X}
  2344. X
  2345. X#ifdef NOREUID
  2346. static int UserPID;
  2347. X#endif
  2348. static int UserSTAT;
  2349. X
  2350. int UserContext()
  2351. X{
  2352. X#ifdef NOREUID
  2353. X  if (eff_uid == real_uid)
  2354. X    return(1);
  2355. X  debug("UserContext: forking.\n");
  2356. X  switch (UserPID = fork())
  2357. X    {
  2358. X    case -1:
  2359. X      Msg(errno, "fork");
  2360. X      return -1;
  2361. X    case 0:
  2362. X      signal(SIGHUP, SIG_DFL);
  2363. X      signal(SIGINT, SIG_IGN);
  2364. X      signal(SIGQUIT, SIG_DFL);
  2365. X      signal(SIGTERM, SIG_DFL);
  2366. X# ifdef BSDJOBS
  2367. X      signal(SIGTTIN, SIG_DFL);
  2368. X      signal(SIGTTOU, SIG_DFL);
  2369. X# endif
  2370. X      setuid(real_uid);
  2371. X      setgid(real_gid);
  2372. X      return 1;
  2373. X    default:
  2374. X      return 0;
  2375. X    }
  2376. X#else
  2377. X  setreuid(eff_uid, real_uid);
  2378. X  setregid(eff_gid, real_gid);
  2379. X  return 1;
  2380. X#endif
  2381. X}
  2382. X
  2383. void
  2384. UserReturn(val)
  2385. int val;
  2386. X{
  2387. X#if defined(NOREUID)
  2388. X  if (eff_uid == real_uid)
  2389. X    UserSTAT = val;
  2390. X  else
  2391. X    exit(val);
  2392. X#else
  2393. X  setreuid(real_uid, eff_uid);
  2394. X  setregid(real_gid, eff_gid);
  2395. X  UserSTAT = val;
  2396. X#endif
  2397. X}
  2398. X
  2399. int UserStatus()
  2400. X{
  2401. X#ifdef NOREUID
  2402. X  int i;
  2403. X# ifdef BSDWAIT
  2404. X  union wait wstat;
  2405. X# else
  2406. X  int wstat;
  2407. X# endif
  2408. X
  2409. X  if (eff_uid == real_uid)
  2410. X    return UserSTAT;
  2411. X  if (UserPID < 0)
  2412. X    return -1;
  2413. X  while ((errno = 0, i = wait(&wstat)) != UserPID)
  2414. X    if (i < 0 && errno != EINTR)
  2415. X      break;
  2416. X  if (i == -1)
  2417. X    return -1;
  2418. X  return (WEXITSTATUS(wstat));
  2419. X#else
  2420. X  return UserSTAT;
  2421. X#endif
  2422. X}
  2423. X
  2424. static void ShowWindows()
  2425. X{
  2426. X  char buf[1024];
  2427. X  register char *s;
  2428. X  register struct win **pp, *p;
  2429. X  register int i, OtherNum = fore->WinLink;
  2430. X  register char *cmd;
  2431. X
  2432. X  for (i = 0, s = buf, pp = wtab; pp < wtab + MAXWIN; ++i, ++pp)
  2433. X    {
  2434. X      if ((p = *pp) == 0)
  2435. X    continue;
  2436. X
  2437. X      if (p->akapos)
  2438. X    {
  2439. X      if (*(p->cmd + p->akapos) && *(p->cmd + p->akapos - 1) != ':')
  2440. X        cmd = p->cmd + p->akapos;
  2441. X      else
  2442. X        cmd = p->cmd + strlen(p->cmd) + 1;
  2443. X    }
  2444. X      else
  2445. X    cmd = p->cmd;
  2446. X      if (s - buf + 5 + (unsigned)strlen(cmd) > fore->width - 1)
  2447. X    break;
  2448. X      if (s > buf)
  2449. X    {
  2450. X      *s++ = ' ';
  2451. X      *s++ = ' ';
  2452. X    }
  2453. X      *s++ = i + '0';
  2454. X      if (i == ForeNum)
  2455. X    *s++ = '*';
  2456. X      else if (i == OtherNum)
  2457. X    *s++ = '-';
  2458. X      if (p->monitor == MON_DONE)
  2459. X    *s++ = '@';
  2460. X      if (p->bell == BELL_DONE)
  2461. X    *s++ = '!';
  2462. X#ifdef UTMPOK
  2463. X      if (p->slot != (slot_t) 0 && p->slot != (slot_t) -1)
  2464. X    *s++ = '$';
  2465. X#endif
  2466. X      if (p->logfp != NULL)
  2467. X    {
  2468. X      strcpy(s, "(L)");
  2469. X      s += 3;
  2470. X    }
  2471. X      *s++ = ' ';
  2472. X      strcpy(s, cmd);
  2473. X      s += strlen(s);
  2474. X      if (i == ForeNum)
  2475. X    {
  2476. X      /* 
  2477. X       * this is usually done by Activate(), but when looking
  2478. X       * on your current window, you may get annoyed, as there is still
  2479. X       * that temporal '!' and '@' displayed.
  2480. X       * So we remove that after displaying it once.
  2481. X       */
  2482. X      p->bell = BELL_OFF;
  2483. X      if (p->monitor != MON_OFF)
  2484. X        p->monitor = MON_ON;
  2485. X    }
  2486. X    }
  2487. X  *s++ = ' ';
  2488. X  *s = '\0';
  2489. X  Msg(0, "%s", buf);
  2490. X}
  2491. X
  2492. X#ifdef LOADAV_3LONGS
  2493. extern long loadav[3];
  2494. X#else
  2495. X# ifdef LOADAV_4LONGS
  2496. extern long loadav[4];
  2497. X# else
  2498. extern double loadav[3];
  2499. X# endif
  2500. X#endif
  2501. extern avenrun;
  2502. X
  2503. static void ShowTime()
  2504. X{
  2505. X  char buf[512];
  2506. X#ifdef LOADAV
  2507. X  char *p;
  2508. X#endif
  2509. X  struct tm *tp;
  2510. X  time_t now;
  2511. X
  2512. X  (void) time(&now);
  2513. X  tp = localtime(&now);
  2514. X  sprintf(buf, "%2d:%02.2d:%02.2d %s", tp->tm_hour, tp->tm_min, tp->tm_sec,
  2515. X      HostName);
  2516. X#ifdef LOADAV
  2517. X  if (avenrun && GetAvenrun())
  2518. X    {
  2519. X      p = buf + strlen(buf);
  2520. X#ifdef LOADAV_3LONGS
  2521. X      sprintf(p, " %2.2f %2.2f %2.2f", (double) loadav[0] / FSCALE,
  2522. X          (double) loadav[1] / FSCALE, (double) loadav[2] / FSCALE);
  2523. X#else
  2524. X#ifdef LOADAV_4LONGS
  2525. X      sprintf(p, " %2.2f %2.2f %2.2f %2.2f", (double) loadav[0] / 100,
  2526. X          (double) loadav[1] / 100, (double) loadav[2] / 100,
  2527. X          (double) loadav[3] / 100);
  2528. X#else
  2529. X      sprintf(p, " %2.2f %2.2f %2.2f", loadav[0], loadav[1], loadav[2]);
  2530. X#endif
  2531. X#endif
  2532. X    }
  2533. X#endif
  2534. X  Msg(0, "%s", buf);
  2535. X}
  2536. X
  2537. static void ShowInfo()
  2538. X{
  2539. X  char buf[512], *p;
  2540. X  register struct win *wp = fore;
  2541. X  register int i;
  2542. X
  2543. X  sprintf(buf, "(%d,%d)/(%d,%d)+%d %cflow%s %cins %corg %cwrap %capp %clog %cmon",
  2544. X      wp->x + 1, wp->y + 1, wp->width, wp->height,
  2545. X      wp->histheight,
  2546. X      wp->flow ? '+' : '-', wp->autoflow ? "(auto)" : "",
  2547. X      wp->insert ? '+' : '-', wp->origin ? '+' : '-',
  2548. X      wp->wrap ? '+' : '-', wp->keypad ? '+' : '-',
  2549. X      (wp->logfp != NULL) ? '+' : '-',
  2550. X      (wp->monitor != MON_OFF) ? '+' : '-');
  2551. X  if (ISO2022)
  2552. X    {
  2553. X      p = buf + strlen(buf);
  2554. X      sprintf(p, " G%1d [", wp->LocalCharset);
  2555. X      for (i = 0; i < 4; i++)
  2556. X    p[i + 5] = wp->charsets[i] ? wp->charsets[i] : 'B';
  2557. X      p[9] = ']';
  2558. X      p[10] = '\0';
  2559. X    }
  2560. X  Msg(0, "%s", buf);
  2561. X}
  2562. X
  2563. X#if defined(sequent) || defined(_SEQUENT_) || defined(SVR4)
  2564. X
  2565. static int OpenPTY()
  2566. X{
  2567. X  char *m, *s;
  2568. X  register int f;
  2569. X# ifdef SVR4
  2570. X  char *ptsname();
  2571. X  sig_t (*sigcld)();
  2572. X
  2573. X  if ((f = open("/dev/ptmx", O_RDWR)) == -1)
  2574. X    return(-1);
  2575. X
  2576. X  /*
  2577. X   * SIGCLD set to SIG_DFL for grantpt() because it fork()s and
  2578. X   * exec()s pt_chmod
  2579. X   */
  2580. X  sigcld = signal(SIGCLD, SIG_DFL);
  2581. X       
  2582. X  if ((m = ptsname(f)) == NULL || unlockpt(f) || grantpt(f))
  2583. X    {
  2584. X      signal(SIGCLD, sigcld);
  2585. X      close(f);
  2586. X      return(-1);
  2587. X    } 
  2588. X  signal(SIGCLD, sigcld);
  2589. X  strncpy(TtyName, m, sizeof TtyName);
  2590. X# else /* SVR4 */
  2591. X  if ((f = getpseudotty(&s, &m)) < 0)
  2592. X    return(-1);
  2593. X  strncpy(PtyName, m, sizeof PtyName);
  2594. X  strncpy(TtyName, s, sizeof TtyName);
  2595. X# endif /* SVR4 */
  2596. X# ifdef POSIX
  2597. X  tcflush(f,TCIOFLUSH);
  2598. X# else
  2599. X  (void) ioctl(f, TIOCFLUSH, (char *) 0);
  2600. X# endif
  2601. X# ifdef LOCKPTY
  2602. X  (void) ioctl(f, TIOCEXCL, (char *) 0);
  2603. X# endif
  2604. X  return (f);
  2605. X}
  2606. X
  2607. X#else /* defined(sequent) || defined(_SEQUENT_) || defined(SVR4) */
  2608. X# if defined(MIPS)
  2609. X#  if !defined(SGI)
  2610. X
  2611. static int OpenPTY()
  2612. X{
  2613. X  register char *p, *l, *d;
  2614. X  register f, tf;
  2615. X  register my_minor;
  2616. X  struct stat buf;
  2617. X   
  2618. X  strcpy(PtyName, PtyProto);
  2619. X  for (p = PtyName; *p != 'X'; ++p)
  2620. X    ;
  2621. X  for (l = "zyxwvutsrqp"; *p = *l; ++l)
  2622. X    {
  2623. X      for (d = "0123456789abcdef"; p[1] = *d; ++d)
  2624. X    {
  2625. X      if ((f = open(PtyName, O_RDWR)) != -1)
  2626. X        {
  2627. X          fstat(f, &buf);
  2628. X          my_minor = minor(buf.st_rdev);
  2629. X          sprintf(TtyName, "/dev/ttyq%d", my_minor);
  2630. X          if ((tf = open(TtyName, O_RDWR)) != -1)
  2631. X        {
  2632. X          close(tf);
  2633. X#ifdef LOCKPTY
  2634. X          (void) ioctl(f, TIOCEXCL, (char *)0);
  2635. X#endif
  2636. X          return f;
  2637. X        }
  2638. X          close(f);
  2639. X        }
  2640. X    }
  2641. X    }
  2642. X  return -1;
  2643. X}
  2644. X
  2645. X#  else  /* SGI */
  2646. X
  2647. static int OpenPTY()
  2648. X{
  2649. X  register f;
  2650. X  register my_minor;
  2651. X  struct stat buf;
  2652. X   
  2653. X  strcpy(PtyName, "/dev/ptc");
  2654. X  f = open(PtyName, O_RDWR|O_NDELAY);
  2655. X  if (f >= 0)
  2656. X    {
  2657. X      if (fstat(f, &buf) < 0)
  2658. X    {
  2659. X      close(f);
  2660. X      return -1;
  2661. X    }
  2662. X      my_minor = minor(buf.st_rdev);
  2663. X      sprintf(TtyName, "/dev/ttyq%d", my_minor);
  2664. X    }
  2665. X  return f;
  2666. X}
  2667. X
  2668. X#  endif /* SGI */
  2669. X# else /* MIPS */
  2670. X
  2671. static int OpenPTY()
  2672. X{
  2673. X  register char *p, *l, *d;
  2674. X  register int i, f, tf;
  2675. X
  2676. X  strcpy(PtyName, PtyProto);
  2677. X  strcpy(TtyName, TtyProto);
  2678. X  for (p = PtyName, i = 0; *p != 'X'; ++p, ++i)
  2679. X    ;
  2680. X#ifdef sequent
  2681. X  /* why ask for sequent in #else (not sequent) section? jw. */
  2682. X  for (l = "p"; (*p = *l) != '\0'; ++l)
  2683. X    {                /* } */
  2684. X      for (d = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; (p[1] = *d) != '\0'; ++d)
  2685. X    {            /* } */
  2686. X#else
  2687. X  for (l = "qpr"; (*p = *l) != '\0'; ++l)
  2688. X    {
  2689. X      for (d = "0123456789abcdef"; (p[1] = *d) != '\0'; ++d)
  2690. X    {
  2691. X#endif
  2692. X      if ((f = open(PtyName, O_RDWR)) != -1)
  2693. X        {
  2694. X          TtyName[i] = p[0];
  2695. X          TtyName[i + 1] = p[1];
  2696. X          if ((tf = open(TtyName, O_RDWR)) != -1)
  2697. X        {
  2698. X          /* close tf, thus we also get rid of an unwanted
  2699. X           * controlling terminal! 
  2700. X           */
  2701. X          close(tf);
  2702. X#ifdef LOCKPTY
  2703. X          (void) ioctl(f, TIOCEXCL, (char *) 0);
  2704. X#endif
  2705. X          return f;
  2706. X        }
  2707. X          close(f);
  2708. X        }
  2709. X    }
  2710. X    }
  2711. X  return -1;
  2712. X}
  2713. X# endif /* MIPS */
  2714. X#endif
  2715. X
  2716. void 
  2717. SetTTY(fd, mp)
  2718. int fd;
  2719. struct mode *mp;
  2720. X{
  2721. X  errno = 0;
  2722. X#ifdef POSIX
  2723. X  tcsetattr(fd, TCSADRAIN, &mp->tio);
  2724. X# ifdef hpux
  2725. X  ioctl(fd, TIOCSLTC, &mp->m_ltchars);
  2726. X# endif
  2727. X#else
  2728. X# ifdef TERMIO
  2729. X  ioctl(fd, TCSETA, &mp->tio);
  2730. X# else
  2731. X  /* ioctl(fd, TIOCSETP, &mp->m_ttyb); */
  2732. X  ioctl(fd, TIOCSETC, &mp->m_tchars);
  2733. X  ioctl(fd, TIOCSLTC, &mp->m_ltchars);
  2734. X  ioctl(fd, TIOCLSET, &mp->m_lmode);
  2735. X  ioctl(fd, TIOCSETD, &mp->m_ldisc);
  2736. X  ioctl(fd, TIOCSETP, &mp->m_ttyb);
  2737. X# endif
  2738. X#endif
  2739. X  if (errno)
  2740. X    Msg(0, "SetTTY: ioctl", fd);
  2741. X}
  2742. X
  2743. void
  2744. GetTTY(fd, mp)
  2745. int fd;
  2746. struct mode *mp;
  2747. X{
  2748. X  errno = 0;
  2749. X#ifdef POSIX
  2750. X  tcgetattr(fd, &mp->tio);
  2751. X# ifdef hpux
  2752. X  ioctl(fd, TIOCGLTC, &mp->m_ltchars);
  2753. X# endif
  2754. X#else
  2755. X# ifdef TERMIO
  2756. X  ioctl(fd, TCGETA, &mp->tio);
  2757. X# else
  2758. X  ioctl(fd, TIOCGETP, &mp->m_ttyb);
  2759. X  ioctl(fd, TIOCGETC, &mp->m_tchars);
  2760. X  ioctl(fd, TIOCGLTC, &mp->m_ltchars);
  2761. X  ioctl(fd, TIOCLGET, &mp->m_lmode);
  2762. X  ioctl(fd, TIOCGETD, &mp->m_ldisc);
  2763. X# endif
  2764. X#endif
  2765. X  if (errno)
  2766. X    Msg(0, "GetTTY: ioctl", fd);
  2767. X}
  2768. X
  2769. void
  2770. SetMode(op, np)
  2771. struct mode *op, *np;
  2772. X{
  2773. X  *np = *op;
  2774. X
  2775. X#if defined(TERMIO) || defined(POSIX)
  2776. X  np->tio.c_iflag &= ~ICRNL;
  2777. X  np->tio.c_oflag &= ~ONLCR;
  2778. X  np->tio.c_lflag &= ~(ICANON | ECHO);
  2779. X  np->tio.c_lflag |= ISIG;
  2780. X/* 
  2781. X * careful, careful catche monkey..
  2782. X * never set VMIN and VTIME to zero, if you want blocking io.
  2783. X */
  2784. X  np->tio.c_cc[VMIN] = 1;
  2785. X  np->tio.c_cc[VTIME] = 0;
  2786. X#ifdef VSTART
  2787. X  startc = op->tio.c_cc[VSTART];
  2788. X#endif
  2789. X#ifdef VSTOP
  2790. X  stopc = op->tio.c_cc[VSTOP];
  2791. X#endif
  2792. X  if (iflag)
  2793. X    intrc = op->tio.c_cc[VINTR];
  2794. X  else
  2795. X    intrc = np->tio.c_cc[VINTR] = 0377;
  2796. X  np->tio.c_cc[VQUIT] = 0377;
  2797. X  if (flowctl == 1)
  2798. X    {
  2799. X      np->tio.c_cc[VINTR] = 0377;
  2800. X#ifdef VSTART
  2801. X      np->tio.c_cc[VSTART] = 0377;
  2802. X#endif
  2803. X#ifdef VSTOP
  2804. X      np->tio.c_cc[VSTOP] = 0377;
  2805. X#endif
  2806. X#ifdef VDISCARD
  2807. X      np->tio.c_cc[VDISCARD] = 0377;
  2808. X#endif
  2809. X      np->tio.c_iflag &= ~IXON;
  2810. X    }
  2811. X#ifdef VSUSP
  2812. X  np->tio.c_cc[VSUSP] = 0377;
  2813. X#endif
  2814. X# ifdef hpux
  2815. X  np->m_ltchars.t_suspc = 0377;
  2816. X  np->m_ltchars.t_dsuspc = 0377;
  2817. X  np->m_ltchars.t_flushc = 0377;
  2818. X  np->m_ltchars.t_lnextc = 0377;
  2819. X# else
  2820. X#  ifdef VDSUSP
  2821. X  np->tio.c_cc[VDSUSP] = 0377;
  2822. X#  endif
  2823. X# endif
  2824. X#else
  2825. X  startc = op->m_tchars.t_startc;
  2826. X  stopc = op->m_tchars.t_stopc;
  2827. X  if (iflag)
  2828. X    intrc = op->m_tchars.t_intrc;
  2829. X  else
  2830. X    intrc = np->m_tchars.t_intrc = -1;
  2831. X  np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
  2832. X  np->m_ttyb.sg_flags |= CBREAK;
  2833. X  np->m_tchars.t_quitc = -1;
  2834. X  if (flowctl == 1)
  2835. X    {
  2836. X      np->m_tchars.t_intrc = -1;
  2837. X      np->m_tchars.t_startc = -1;
  2838. X      np->m_tchars.t_stopc = -1;
  2839. X    }
  2840. X  np->m_ltchars.t_suspc = -1;
  2841. X  np->m_ltchars.t_dsuspc = -1;
  2842. X  np->m_ltchars.t_flushc = -1;
  2843. X  np->m_ltchars.t_lnextc = -1;
  2844. X#endif                /* defined(TERMIO) || defined(POSIX) */
  2845. X}
  2846. X
  2847. void
  2848. SetFlow(on)
  2849. int on;
  2850. X{
  2851. X#if defined(TERMIO) || defined(POSIX)
  2852. X  if (on)
  2853. X    {
  2854. X      NewMode.tio.c_cc[VINTR] = intrc;
  2855. X#ifdef VSTART
  2856. X      NewMode.tio.c_cc[VSTART] = startc;
  2857. X#endif
  2858. X#ifdef VSTOP
  2859. X      NewMode.tio.c_cc[VSTOP] = stopc;
  2860. X#endif
  2861. X      NewMode.tio.c_iflag |= IXON;
  2862. X    }
  2863. X  else
  2864. X    {
  2865. X      NewMode.tio.c_cc[VINTR] = 0377;
  2866. X#ifdef VSTART
  2867. X      NewMode.tio.c_cc[VSTART] = 0377;
  2868. X#endif
  2869. X#ifdef VSTOP
  2870. X      NewMode.tio.c_cc[VSTOP] = 0377;
  2871. X#endif
  2872. X      NewMode.tio.c_iflag &= ~IXON;
  2873. X    }
  2874. X# ifdef POSIX
  2875. X  if (tcsetattr(0, TCSADRAIN, &NewMode.tio))
  2876. X# else
  2877. X  if (ioctl(0, TCSETA, &NewMode.tio) != 0)
  2878. X# endif
  2879. X    debug1("SetFlow: ioctl errno %d\n", errno);
  2880. X#else
  2881. X  if (on)
  2882. X    {
  2883. X      NewMode.m_tchars.t_intrc = intrc;
  2884. X      NewMode.m_tchars.t_startc = startc;
  2885. X      NewMode.m_tchars.t_stopc = stopc;
  2886. X    }
  2887. X  else
  2888. X    {
  2889. X      NewMode.m_tchars.t_intrc = -1;
  2890. X      NewMode.m_tchars.t_startc = -1;
  2891. X      NewMode.m_tchars.t_stopc = -1;
  2892. X    }
  2893. X  if (ioctl(0, TIOCSETC, &NewMode.m_tchars) != 0)
  2894. X    debug1("SetFlow: ioctl errno %d\n", errno);
  2895. X#endif                /* defined(TERMIO) || defined(POSIX) */
  2896. X}
  2897. X
  2898. char *GetTtyName()
  2899. X{
  2900. X  register char *p;
  2901. X  register int n;
  2902. X
  2903. X  for (p = 0, n = 0; n <= 2 && ((p = ttyname(n)) == 0); n++)
  2904. X    ;
  2905. X  if (!p || *p == '\0')
  2906. X    Msg(0, "screen must run on a tty.");
  2907. X  return p;
  2908. X}
  2909. X
  2910. X/* we return 1 if we could attach one, or 0 if none */
  2911. static int Attach(how)
  2912. int how;
  2913. X{
  2914. X  int lasts;
  2915. X  struct msg m;
  2916. X  struct stat st;
  2917. X  char *tty, *s;
  2918. X
  2919. X  if (how == MSG_WINCH)
  2920. X    {
  2921. X      bzero((char *) &m, sizeof(m));
  2922. X      m.type = how;
  2923. X      if ((lasts=MakeClientSocket(0,SockName))>=0)
  2924. X    {
  2925. X          write(lasts, &m, sizeof(m));
  2926. X          close(lasts);
  2927. X    }
  2928. X      return 0;
  2929. X    }
  2930. X
  2931. X  switch (FindSocket(how, &lasts))
  2932. X    {
  2933. X    case 0:
  2934. X      if (rflag == 2)
  2935. X    return 0;
  2936. X      if (quietflag)
  2937. X    eexit(10);
  2938. X      Msg(0, "There is no screen to be %sed.", dflag ? "detach" : "resum");
  2939. X      /* NOTREACHED */
  2940. X    case 1:
  2941. X      break;
  2942. X    default:
  2943. X      Msg(0, "Type \"screen [-d] -r host.tty\" to resume one of them.");
  2944. X      /* NOTREACHED */
  2945. X    }
  2946. X  SockName = SockNamePtr;
  2947. X  debug1("Attach decided, it is '%s'\n", SockPath);
  2948. X  if (stat(SockPath, &st) == -1)
  2949. X    Msg(errno, "stat %s", SockPath);
  2950. X  if ((st.st_mode & 0700) != (dflag ? 0700 : 0600))
  2951. X    Msg(0, "That screen is %sdetached.", dflag ? "already " : "not ");
  2952. X  tty = GetTtyName();
  2953. X  if ((unsigned)strlen(tty) >= MAXPATH)
  2954. X    Msg(0, "TtyName too long - sorry.");
  2955. X#ifdef REMOTE_DETACH
  2956. X  if (dflag &&
  2957. X      (how == MSG_ATTACH || how == MSG_DETACH || how == MSG_POW_DETACH))
  2958. X    {
  2959. X      strcpy(m.m.detach.tty, tty);
  2960. X      m.m.detach.dpid = getpid();
  2961. X#ifdef POW_DETACH
  2962. X      if (dflag == 2)
  2963. X    m.type = MSG_POW_DETACH;
  2964. X      else
  2965. X#endif
  2966. X    m.type = MSG_DETACH;
  2967. X      trysend(lasts, &m, m.m.detach.password);
  2968. X      if (how != MSG_ATTACH)
  2969. X    return 0;        /* we detached it. jw. */
  2970. X      sleep(1);            /* we dont want to overrun our poor backend. jw. */
  2971. X      if ((lasts = MakeClientSocket(0, SockName)) == -1)
  2972. X    Msg(0, "Cannot contact screen again. Shit.");
  2973. X    }
  2974. X#endif
  2975. X  m.type = how;
  2976. X  strcpy(m.m.attach.tty, tty);
  2977. X  s = getenv("TERM");
  2978. X  if (s)
  2979. X    {
  2980. X      if ((unsigned)strlen(s) >= MAXPATH-5)
  2981. X    Msg(0, "$TERM too long - sorry.");
  2982. X      sprintf(m.m.attach.envterm, "TERM=%s", s);
  2983. X    }
  2984. X  else
  2985. X    *m.m.attach.envterm = '\0';
  2986. X  debug1("attach: sending %d bytes... ", sizeof m);
  2987. X
  2988. X  m.m.attach.apid = getpid();
  2989. X  m.m.attach.adaptflag = adaptflag;
  2990. X  m.m.attach.lines = m.m.attach.columns = 0;
  2991. X  if (s = getenv("LINES"))
  2992. X    m.m.attach.lines = atoi(s);
  2993. X  if (s = getenv("COLUMNS"))
  2994. X    m.m.attach.columns = atoi(s);
  2995. X
  2996. X  trysend(lasts, &m, m.m.attach.password);
  2997. X  debug1("Attach(%d): sent\n", m.type);
  2998. X  Suspended = 0;
  2999. X  rflag = 0;
  3000. X  return 1;
  3001. X}
  3002. X
  3003. X
  3004. X#ifdef PASSWORD
  3005. X
  3006. static trysendstat;
  3007. X
  3008. static sig_t trysendok(SIGDEFARG)
  3009. X{
  3010. X  trysendstat = 1;
  3011. X}
  3012. X
  3013. static sig_t trysendfail(SIGDEFARG)
  3014. X{
  3015. X  trysendstat = -1;
  3016. X}
  3017. X
  3018. static char screenpw[9];
  3019. X
  3020. static void trysend(fd, m, pwto)
  3021. int fd;
  3022. struct msg *m;
  3023. char *pwto;
  3024. X{
  3025. X  char *npw = NULL;
  3026. X  sig_t (*sighup)();
  3027. X  sig_t (*sigusr1)();
  3028. X
  3029. X  sigusr1 = signal(SIG_PW_OK, trysendok);
  3030. X  sighup = signal(SIG_PW_FAIL, trysendfail);
  3031. X  for (;;)
  3032. X    {
  3033. X      strcpy(pwto, screenpw);
  3034. X      trysendstat = 0;
  3035. X      if (write(fd, (char *) m, sizeof(*m)) != sizeof(*m))
  3036. X    Msg(errno, "write");
  3037. X      close(fd);
  3038. X      while (trysendstat == 0)
  3039. X    pause();
  3040. X      if (trysendstat > 0)
  3041. X    {
  3042. X      signal(SIG_PW_OK, sigusr1);
  3043. X      signal(SIG_PW_FAIL, sighup);
  3044. X      return;
  3045. X    }
  3046. X      if (*screenpw || (npw = getpass("Screen Password:")) == 0 || *npw == 0)
  3047. X    Msg(0, "Password incorrect");
  3048. X      strncpy(screenpw,npw,8);
  3049. X      if ((fd = MakeClientSocket(0, SockName)) == -1)
  3050. X    Msg(0, "Cannot contact screen again. Shit.");
  3051. X#ifdef SYSV
  3052. X      signal(SIG_PW_FAIL, trysendfail);
  3053. X#endif
  3054. X    }
  3055. X}
  3056. X
  3057. X#else /* PASSWORD */
  3058. X
  3059. static trysend(fd, m, pwto)
  3060. struct msg *m;
  3061. char *pwto;
  3062. X{
  3063. X  strcpy(pwto, "");
  3064. X  if (write(fd, (char *) m, sizeof(*m)) != sizeof(*m))
  3065. X    Msg(errno, "write");
  3066. X  close(fd);
  3067. X}
  3068. X
  3069. X#endif /* PASSWORD */
  3070. X
  3071. X
  3072. X/*
  3073. X * Unfortunatelly this is also the SIGHUP handler, so we have to
  3074. X * check, if the backend is already detached.
  3075. X */
  3076. X
  3077. static sig_t AttacherFinit(SIGDEFARG)
  3078. X{
  3079. X  struct stat statb;
  3080. X  struct msg m;
  3081. X  int s;
  3082. X
  3083. X  debug("AttacherFinit();\n");
  3084. X  /* Check if signal comes from backend */
  3085. X  if (SockName)
  3086. X    {
  3087. X      strcpy(SockNamePtr, SockName);
  3088. X      if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
  3089. X    {
  3090. X      debug("Detaching backend!\n");
  3091. X      bzero((char *) &m, sizeof(m));
  3092. X      strcpy(m.m.detach.tty, GetTtyName());
  3093. X      m.m.detach.dpid = getpid();
  3094. X#ifdef PASSWORD
  3095. X      strcpy(m.m.detach.password, screenpw);
  3096. X      signal(SIG_PW_OK, SIG_IGN);
  3097. X      signal(SIG_PW_FAIL, SIG_IGN);
  3098. X#endif
  3099. X      m.type = MSG_HANGUP;
  3100. X      if ((s=MakeClientSocket(0, SockName))>=0)
  3101. X        {
  3102. X          write(s, &m, sizeof(m));
  3103. X          close(s);
  3104. X        }
  3105. X    }
  3106. X    }
  3107. X  exit(0);
  3108. X#ifndef SIGVOID
  3109. X  return((sig_t) 0);
  3110. X#endif
  3111. X}
  3112. X
  3113. X#ifdef POW_DETACH
  3114. static sig_t AttacherFinitBye(SIGDEFARG)
  3115. X{
  3116. X  int ppid;
  3117. X  debug("AttacherFintBye()\n");
  3118. X  freetty();
  3119. X  setuid(real_uid);
  3120. X  setgid(real_gid);
  3121. X  /* we don't want to disturb init (even if we were root), eh? jw */
  3122. X  if ((ppid = getppid()) > 1)
  3123. X    Kill(ppid, SIGHUP);        /* carefully say good bye. jw. */
  3124. X  exit(0);
  3125. X#ifndef SIGVOID
  3126. X  return((sig_t) 0);
  3127. X#endif
  3128. X}
  3129. X#endif
  3130. X
  3131. static SuspendPlease;
  3132. X
  3133. static sig_t SigStop(SIGDEFARG)
  3134. X{
  3135. X  debug("SigStop()\n");
  3136. X  SuspendPlease = 1;
  3137. X#ifndef SIGVOID
  3138. X  return((sig_t) 0);
  3139. X#endif
  3140. X}
  3141. X
  3142. X#ifdef LOCK
  3143. static LockPlease;
  3144. X
  3145. static sig_t DoLock(SIGDEFARG)
  3146. X{
  3147. X  debug("DoLock()\n");
  3148. X  LockPlease = 1;
  3149. X# ifdef SYSV
  3150. X  signal(SIG_LOCK, DoLock);
  3151. X# endif
  3152. X# ifndef SIGVOID
  3153. X  return((sig_t) 0);
  3154. X# endif
  3155. X}
  3156. X#endif
  3157. X
  3158. X#if defined(SIGWINCH) && defined(TIOCGWINSZ)
  3159. static SigWinchPlease;
  3160. X
  3161. static sig_t SigAttWinch(SIGDEFARG)
  3162. X{
  3163. X  debug("SigAttWinch()\n");
  3164. X  SigWinchPlease = 1;
  3165. X# ifndef SIGVOID
  3166. X  return((sig_t) 0);
  3167. X# endif
  3168. X}
  3169. X#endif
  3170. X
  3171. static void Attacher()
  3172. X{
  3173. X  /*
  3174. X   * permanent in UserContext. Advantage is, you can kill your attacher
  3175. X   * when things go wrong. Any disadvantages? jw.
  3176. X   */
  3177. X  setuid(real_uid);
  3178. X  setgid(real_gid);
  3179. X
  3180. X  signal(SIGHUP, AttacherFinit);
  3181. X  signal(SIG_BYE, AttacherFinit);
  3182. X#ifdef POW_DETACH
  3183. X  signal(SIG_POWER_BYE, AttacherFinitBye);
  3184. X#endif
  3185. X#ifdef LOCK
  3186. X  signal(SIG_LOCK, DoLock);
  3187. X#endif
  3188. X  signal(SIGINT, SIG_IGN);
  3189. X#ifdef BSDJOBS
  3190. X  signal(SIG_STOP, SigStop);
  3191. X#endif
  3192. X#if defined(SIGWINCH) && defined(TIOCGWINSZ)
  3193. X  signal(SIGWINCH, SigAttWinch);
  3194. X#endif
  3195. X#ifdef DEBUG
  3196. X# ifdef SYSV
  3197. X  signal(SIGCLD,FEChld);
  3198. X# else
  3199. X  signal(SIGCHLD,FEChld);
  3200. X# endif
  3201. X#endif
  3202. X  debug("attacher: going for a nap.\n");
  3203. X  dflag = 0;
  3204. X  while (1)
  3205. X    {
  3206. X      pause();
  3207. X      debug("attacher: huh! a signal!\n");
  3208. X#ifdef DEBUG
  3209. X      if (FEpanic)
  3210. X        {
  3211. X      printf("\n\rSuddenly the Dungeon collapses!! - You die...\n\r");
  3212. X      SetTTY(0, &OldMode);
  3213. X      eexit(1);
  3214. X        }
  3215. X#endif
  3216. X#ifdef BSDJOBS
  3217. X      if (SuspendPlease)
  3218. X    {
  3219. X      SuspendPlease = 0;
  3220. X      signal(SIGTSTP, SIG_DFL);
  3221. X      debug("attacher: killing myself SIGTSTP\n");
  3222. X      kill(getpid(), SIGTSTP);
  3223. X
  3224. X      debug1("attacher: continuing from stop(%d)\n", Suspended);
  3225. X      signal(SIG_STOP, SigStop);
  3226. X      (void) Attach(MSG_CONT);
  3227. X    }
  3228. X#endif
  3229. X#ifdef LOCK
  3230. X      if (LockPlease)
  3231. X    {
  3232. X      LockPlease = 0;
  3233. X      LockTerminal();
  3234. X# ifdef SYSV
  3235. X      signal(SIG_LOCK, DoLock);
  3236. X# endif
  3237. X      (void) Attach(MSG_CONT);
  3238. X    }
  3239. X#endif    /* LOCK */
  3240. X#if defined(SIGWINCH) && defined(TIOCGWINSZ)
  3241. X      if (SigWinchPlease)
  3242. X    {
  3243. X      SigWinchPlease = 0;
  3244. X# ifdef SYSV
  3245. X      signal(SIGWINCH, SigAttWinch);
  3246. X# endif
  3247. X      (void) Attach(MSG_WINCH);
  3248. X    }
  3249. X#endif    /* SIGWINCH */
  3250. X    }
  3251. X}
  3252. X
  3253. X#ifdef LOCK
  3254. X
  3255. X/* ADDED by Rainer Pruy 10/15/87 */
  3256. X/* POLISHED by mls. 03/10/91 */
  3257. X
  3258. static char LockEnd[] = "Welcome back to screen !!\n";
  3259. X
  3260. static void LockTerminal()
  3261. X{
  3262. X  char *prg;
  3263. X  int sig, pid;
  3264. X  sig_t (*sigs[NSIG])__P(SIGPROTOARG);
  3265. X
  3266. X  for (sig = 1; sig < NSIG; sig++)
  3267. X    {
  3268. X      sigs[sig] = signal(sig, SIG_IGN);
  3269. X    }
  3270. X  SetTTY(0, &OldMode);
  3271. X  printf("\n");
  3272. X
  3273. X  prg = getenv("LOCKPRG");
  3274. X  if (prg && strcmp(prg,"builtin") && !access(prg, X_OK))
  3275. X    {
  3276. X      debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
  3277. X      if ((pid = fork()) == 0)
  3278. X        {
  3279. X          /* Child */
  3280. X          setuid(real_uid);    /* this should be done already */
  3281. X          setgid(real_gid);
  3282. X          execl(prg, "SCREEN-LOCK", NULL);
  3283. X          exit(errno);
  3284. X        }
  3285. X      if (pid == -1)
  3286. X        {
  3287. X#ifdef NETHACK
  3288. X          if (nethackflag)
  3289. X            Msg(errno, "Cannot fork terminal - lock failed");
  3290. X          else
  3291. X#endif
  3292. X          Msg(errno, "Cannot lock terminal - fork failed");
  3293. X        }
  3294. X      else
  3295. X        {
  3296. X#ifdef BSDWAIT
  3297. X          union wait wstat;
  3298. X#else
  3299. X          int wstat;
  3300. X#endif
  3301. X          int wret;
  3302. X
  3303. X#ifdef hpux
  3304. X          signal(SIGCLD, SIG_DFL);
  3305. X#endif
  3306. X          errno = 0;
  3307. X          while (((wret = wait((int *) &wstat)) != pid) ||
  3308. X             ((wret == -1) && (errno == EINTR))
  3309. X             )
  3310. X        errno = 0;
  3311. X    
  3312. X          if (errno)
  3313. X        {
  3314. X          perror("Lock");
  3315. X          sleep(2);
  3316. X        }
  3317. X      else if (WTERMSIG(wstat) != 0)
  3318. X        {
  3319. X          fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
  3320. X              WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
  3321. X          sleep(2);
  3322. X        }
  3323. X      else if (WEXITSTATUS(wstat))
  3324. X        {
  3325. X          debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
  3326. X        }
  3327. X          else
  3328. X        printf(LockEnd);
  3329. X        }
  3330. X    }
  3331. X  else
  3332. X    {
  3333. X      if (prg)
  3334. X    {
  3335. X          debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
  3336. X    }
  3337. X      else
  3338. X    {
  3339. X      debug("lockterminal: using buitin.\n");
  3340. X    }
  3341. X      screen_builtin_lck();
  3342. X    }
  3343. X  /* reset signals */
  3344. X  for (sig = 1; sig < NSIG; sig++)
  3345. X    {
  3346. X      if (sigs[sig] != (sig_t(*) ()) - 1)
  3347. X    signal(sig, sigs[sig]);
  3348. X    }
  3349. X}                /* LockTerminal */
  3350. X
  3351. X/* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
  3352. void
  3353. screen_builtin_lck()
  3354. X{
  3355. X  char fullname[100],*cp1, message[BUFSIZ];
  3356. X  char c,*pass,mypass[9];
  3357. X  int t;
  3358. X
  3359. X#ifdef undef
  3360. X  /* get password entry */
  3361. X  if ((ppp = getpwuid(real_uid)) == NULL)
  3362. X    {
  3363. X      fprintf(stderr,"screen_builtin_lck: No passwd entry.\007\n");
  3364. X      sleep(2);
  3365. X      return;
  3366. X    }
  3367. X  if (!isatty(0))
  3368. X    {
  3369. X      fprintf(stderr,"screen_builtin_lck: Not a tty.\007\n");
  3370. X      sleep(2);
  3371. X      return;
  3372. X    }
  3373. X#endif
  3374. X  for (t=0; t<13; t++)
  3375. X    {
  3376. X    c=ppp->pw_passwd[t];
  3377. X    if (!(c == '.' || c == '/' ||
  3378. X          c>='0' && c<='9' || 
  3379. X          c>='a' && c<='z' || 
  3380. X          c>='A' && c<='Z')) break;
  3381. X    }
  3382. X  if (t<13)
  3383. X    {
  3384. X      debug("builtin_lock: ppp->pw_passwd bad, has it a shadow?\n");
  3385. X      if (pass=getpass("Key:   "))
  3386. X        {
  3387. X          strncpy(mypass,pass,8);
  3388. X          mypass[8]=0;
  3389. X          if (*mypass==0)
  3390. X            return;
  3391. X          if (pass=getpass("Again: "))
  3392. X            {
  3393. X              if (strcmp(mypass,pass))
  3394. X                {
  3395. X                  fprintf(stderr,"Passwords don't match.\007\n");
  3396. X                  sleep(2);
  3397. X                  return;
  3398. X                }
  3399. X            }
  3400. X        }
  3401. X      if (pass==0)
  3402. X        {
  3403. X          fprintf(stderr,"Getpass error.\007\n");
  3404. X          sleep(2);
  3405. X          return;
  3406. X        }
  3407. X      pass=0;
  3408. X    }
  3409. X  else pass=ppp->pw_passwd;
  3410. X
  3411. X  debug("screen_builtin_lck looking in gcos field\n");
  3412. X  strcpy(fullname,ppp->pw_gecos);
  3413. X  if ((cp1 = index(fullname,',')) != NULL)
  3414. X    *cp1 = '\0';
  3415. X  if ((cp1 = index(fullname,'&')) != NULL)
  3416. X    {
  3417. X      sprintf(cp1,"%s",ppp->pw_name);
  3418. X      *cp1 = islower(*cp1) ? toupper(*cp1) : *cp1;
  3419. X    }
  3420. X
  3421. X  sprintf(message,"Screen used by %s <%s>.\nPassword:\007",
  3422. X          fullname, ppp->pw_name);
  3423. X
  3424. X  /* loop here to wait for correct password */
  3425. X  for (;;)
  3426. X    {
  3427. X      debug("screen_builtin_lck awaiting password\n");
  3428. X      if (pass)
  3429. X        {
  3430. X          if(!strcmp(crypt(getpass(message),pass),pass))
  3431. X            break;
  3432. X        }
  3433. X      else
  3434. X        {
  3435. X          if(!strcmp(getpass(message),mypass))
  3436. X            break;
  3437. X        }
  3438. X      debug("screen_builtin_lck: NO!!!!!\n");
  3439. X    }
  3440. X  debug("password ok.\n");
  3441. X}
  3442. X
  3443. X#endif    /* LOCK */
  3444. X
  3445. X/*
  3446. X * Detach now has the following modes:
  3447. X *    D_DETACH    SIG_BYE        detach backend and exit attacher
  3448. X *    D_STOP        SIG_STOP    stop attacher (and detach backend)
  3449. X *    D_REMOTE    SIG_BYE        remote detach -- reattach to new attacher
  3450. X *    D_POWER     SIG_POWER_BYE     power detach -- attacher kills his parent
  3451. X *    D_REMOTE_POWER    SIG_POWER_BYE    remote power detach -- both
  3452. X *    D_LOCK        SIG_LOCK    lock the attacher
  3453. X * (jw)
  3454. X * we always remove our utmp slots. (even when "lock" or "stop")
  3455. X * Note: Take extra care here, we may be called by unterrupt!
  3456. X */
  3457. void
  3458. Detach(mode)
  3459. int mode;
  3460. X{
  3461. X  int sign = 0;
  3462. X#ifdef UTMPOK
  3463. X  register int n;
  3464. X#endif
  3465. X
  3466. X  if (Detached)
  3467. X    return;
  3468. X  debug1("Detach(%d)\n", mode);
  3469. X  if (fore && status)
  3470. X    RemoveStatus();
  3471. X  signal(SIGHUP, SIG_IGN);
  3472. X  SetTTY(0, &OldMode);
  3473. X  FinitTerm();
  3474. X  switch (mode)
  3475. X    {
  3476. X    case D_DETACH:
  3477. X      printf("\n[detached]\n");
  3478. X      sign = SIG_BYE;
  3479. X      break;
  3480. X#ifdef BSDJOBS
  3481. X    case D_STOP:
  3482. X      (void) fflush(stdout);
  3483. X      sign = SIG_STOP;
  3484. X      break;
  3485. X#endif
  3486. X#ifdef REMOTE_DETACH
  3487. X    case D_REMOTE:
  3488. X      printf("\n[remote detached]\n");
  3489. X      sign = SIG_BYE;
  3490. X      break;
  3491. X#endif
  3492. X#ifdef POW_DETACH
  3493. X    case D_POWER:
  3494. X      printf("\n[power detached]\n");
  3495. X      if (PowDetachString) 
  3496. X        printf("%s\n",PowDetachString);
  3497. X      sign = SIG_POWER_BYE;
  3498. X      break;
  3499. X#ifdef REMOTE_DETACH
  3500. X    case D_REMOTE_POWER:
  3501. X      printf("\n[remote power detached]\n");
  3502. X      if (PowDetachString) 
  3503. X        printf("%s\n",PowDetachString);
  3504. X      sign = SIG_POWER_BYE;
  3505. X      break;
  3506. X#endif
  3507. X#endif
  3508. X    case D_LOCK:
  3509. X      ClearDisplay();
  3510. X      sign = SIG_LOCK;
  3511. X      /* tell attacher to lock terminal with a lockprg. */
  3512. X      break;
  3513. X    }
  3514. X#ifdef UTMPOK
  3515. X  for (n = WinList; n != -1; n = wtab[n]->WinLink)
  3516. X    if (wtab[n]->slot != (slot_t) -1)
  3517. X      {
  3518. X    RemoveUtmp(wtab[n]);
  3519. X        /*
  3520. X     * Set the slot to 0 to get the window
  3521. X         * logged in again.
  3522. X     */
  3523. X    wtab[n]->slot = (slot_t) 0;
  3524. X      }
  3525. X  RestoreLoginSlot();
  3526. X#endif
  3527. X  freetty();
  3528. X  debug("Detach: we did freetty().\n");
  3529. X  (void) chmod(SockPath, /* S_IFSOCK | */ 0600); /* Flag detached-ness */
  3530. X    /*
  3531. X     * tell father to father what to do. We do that after we
  3532. X     * freed the tty, thus getty feels more comfortable on hpux
  3533. X     * if it was a power detach.
  3534. X     */
  3535. X  Kill(AttacherPid,sign);
  3536. X  debug2("Detach: Signal %d to Attacher(%d)!\n", sign, AttacherPid);
  3537. X  if (mode != D_LOCK && mode != D_STOP)
  3538. X    AttacherPid = 0;
  3539. X
  3540. X  Detached = 1;
  3541. X  Suspended = (mode == D_STOP) ? 1 : 0;
  3542. X  if (fore)
  3543. X    fore->active = 0;
  3544. X  debug("Detach returns, we are successfully detached.\n");
  3545. X}
  3546. X
  3547. int
  3548. CheckPid(pid)
  3549. int pid;
  3550. X{
  3551. X  if (pid < 2)
  3552. X    return(-1);
  3553. X  if (eff_uid == real_uid)
  3554. X    return kill(pid, 0);
  3555. X  if (UserContext() == 1)
  3556. X    {
  3557. X      UserReturn(kill(pid, 0));
  3558. X    }
  3559. X  return UserStatus();
  3560. X}
  3561. X
  3562. void
  3563. Kill(pid, sig)
  3564. int pid, sig;
  3565. X{
  3566. X  if (pid < 2)
  3567. X    return;
  3568. X  (void) kill(pid, sig);
  3569. X}
  3570. X
  3571. static int IsSymbol(e, s)
  3572. register char *e, *s;
  3573. X{
  3574. X  register char *p;
  3575. X  register int n;
  3576. X
  3577. X  for (p = e; *p && *p != '='; ++p)
  3578. X    ;
  3579. X  if (*p)
  3580. X    {
  3581. X      *p = '\0';
  3582. X      n = strcmp(e, s);
  3583. X      *p = '=';
  3584. X      return n == 0;
  3585. X    }
  3586. X  return 0;
  3587. X}
  3588. X
  3589. static void MakeNewEnv()
  3590. X{
  3591. X  register char **op, **np;
  3592. X  static char buf[MAXSTR];
  3593. X
  3594. X  for (op = environ; *op; ++op)
  3595. X    ;
  3596. X  NewEnv = np = (char **) malloc((unsigned) (op - environ + 6 + 1) * sizeof(char **));
  3597. X  if (!NewEnv)
  3598. X    Msg_nomem;
  3599. X  if ((unsigned)strlen(SockName) > MAXSTR - 5)
  3600. X    SockName = "?";
  3601. X  sprintf(buf, "STY=%s", SockName);
  3602. X  *np++ = buf;                    /* NewEnv[0] */
  3603. X  *np++ = Term;                    /* NewEnv[1] */
  3604. X#ifdef TIOCGWINSZ
  3605. X  np += 2;            /* leave room for TERMCAP and WINDOW */
  3606. X#else
  3607. X  np += 4;    /* room for TERMCAP WINDOW LINES COLUMNS */
  3608. X#endif
  3609. X
  3610. X  for (op = environ; *op; ++op)
  3611. X    {
  3612. X      if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
  3613. X      && !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
  3614. X      && !IsSymbol(*op, "SCREENCAP")
  3615. X#ifndef TIOCGWINSZ
  3616. X      && !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
  3617. X#endif
  3618. X      )
  3619. X    *np++ = *op;
  3620. X    }
  3621. X  *np = 0;
  3622. X}
  3623. X
  3624. void
  3625. X#ifdef USEVARARGS
  3626. X/*VARARGS2*/
  3627. X# if defined(__STDC__)
  3628. Msg(int err, char *fmt, ...)
  3629. X# else
  3630. Msg(err, fmt, va_alist)
  3631. int err;
  3632. char *fmt;
  3633. va_dcl
  3634. X# endif
  3635. X{
  3636. X  static va_list ap = 0;
  3637. X#else
  3638. X/*VARARGS2*/
  3639. Msg(err, fmt, p1, p2, p3, p4, p5, p6)
  3640. int err;
  3641. char *fmt;
  3642. unsigned long p1, p2, p3, p4, p5, p6;
  3643. X{
  3644. X#endif
  3645. X  char buf[MAXPATH*2];
  3646. X  char *p = buf;
  3647. X
  3648. X  if (Detached)
  3649. X    return;
  3650. X#ifdef USEVARARGS
  3651. X# if defined(__STDC__)
  3652. X  va_start(ap, fmt);
  3653. X# else
  3654. X  va_start(ap);
  3655. X# endif
  3656. X  (void) vsprintf(p, fmt, ap);
  3657. X  va_end(ap);
  3658. X#else
  3659. X  sprintf(p, fmt, p1, p2, p3, p4, p5, p6);
  3660. X#endif
  3661. X  if (err)
  3662. X    {
  3663. X      p += strlen(p);
  3664. X      if (err > 0 && err < sys_nerr)
  3665. X    sprintf(p, ": %s", sys_errlist[err]);
  3666. X      else
  3667. X    sprintf(p, ": Error %d", err);
  3668. X    }
  3669. X  if (HasWindow)
  3670. X    {
  3671. X      debug1("Msg('%s');\n", p);
  3672. X      MakeStatus(buf);
  3673. X    }
  3674. X  else
  3675. X    {
  3676. X      printf("%s\r\n", buf);
  3677. X      if (DeadlyMsg)
  3678. X    {
  3679. X          debug1("Msg('%s') screen is not up, exiting..\n", buf);
  3680. X          Kill(AttacherPid, SIG_BYE);
  3681. X          eexit(1);
  3682. X    }
  3683. X      else
  3684. X    debug1("Harmless = 0; Msg('%s');\n", buf);
  3685. X    }
  3686. X  DeadlyMsg = 1;
  3687. X}
  3688. X
  3689. char *Filename(s)
  3690. char *s;
  3691. X{
  3692. X  register char *p;
  3693. X
  3694. X  if (s == NULL) 
  3695. X    return s;
  3696. X  p = s + strlen(s) - 1;
  3697. X  while (p >= s && *p != '/')
  3698. X    --p;
  3699. X  return ++p;
  3700. X}
  3701. X
  3702. X/*
  3703. X * '^' is allowed as an escape mechanism for control characters. jw.
  3704. X */
  3705. static char *MakeWinMsg(s, n)
  3706. register char *s;
  3707. int n;
  3708. X{
  3709. X  static char buf[MAXSTR];
  3710. X  register char *p = buf;
  3711. X  register int ctrl;
  3712. X
  3713. X  ctrl = 0;
  3714. X  for (; *s && p < buf + MAXSTR - 1; s++, p++)
  3715. X    if (ctrl)
  3716. X      {
  3717. X        ctrl = 0;
  3718. X        if (*s == '^' || *s < 64)
  3719. X          *p = *s;
  3720. X        else 
  3721. X          *p = *s - 64;
  3722. X      }
  3723. X    else
  3724. X      {
  3725. X        switch (*s)
  3726. X          {
  3727. X          case '%':
  3728. X            *p = n + '0';
  3729. X        break;
  3730. X          case '~':
  3731. X        *p = BELL;
  3732. X        break;
  3733. X      case '^':
  3734. X        ctrl = 1;
  3735. X        *p-- = '^';
  3736. X        break;
  3737. X          default:
  3738. X        *p = *s;
  3739. X        break;
  3740. X          }
  3741. X      }
  3742. X  *p = '\0';
  3743. X  return buf;
  3744. X}
  3745. X
  3746. END_OF_FILE
  3747. if test 78493 -ne `wc -c <'screen.c'`; then
  3748.     echo shar: \"'screen.c'\" unpacked with wrong size!
  3749. fi
  3750. # end of 'screen.c'
  3751. fi
  3752. echo shar: End of archive 8 \(of 8\).
  3753. cp /dev/null ark8isdone
  3754. MISSING=""
  3755. for I in 1 2 3 4 5 6 7 8 ; do
  3756.     if test ! -f ark${I}isdone ; then
  3757.     MISSING="${MISSING} ${I}"
  3758.     fi
  3759. done
  3760. if test "${MISSING}" = "" ; then
  3761.     echo You have unpacked all 8 archives.
  3762.     rm -f ark[1-9]isdone
  3763. else
  3764.     echo You still need to unpack the following archives:
  3765.     echo "        " ${MISSING}
  3766. fi
  3767. ##  End of shell archive.
  3768. exit 0
  3769.